- What Is a Joomla! Template?
- The Localhost Design Process
- W3C and Tableless Design
- Creating a Simple Template: 960TemplateTutorialStep1
- Using CSS to Create a Tableless Layout: CSSTemplateTutorialStep2
- Making a Real Joomla! 1.6 Template: 960TemplateTutorialStep3
- Summary
Using CSS to Create a Tableless Layout: CSSTemplateTutorialStep2
In this section, you will use pure CSS to make a three-column layout for the Joomla template. You will also be making it a "fixed" layout. There are three main types of web page layouts—fixed, fluid, and jello—and they all refer to how the width of the page is controlled.
A fixed layout has the width set to some fixed value. A fluid layout can grow and shrink to the browser window, and a jello layout is fluid but between some minimum and maximum values.
A few years ago, fluid width templates were all the rage. Accessibility guys loved them, and it was cool to grab the corner of your browser window and see all that content slide around.
But now, I don't make fluid templates, but focus on fixed width templates. I firmly believe they are the best fit on today's Web. Four years ago, many people were still using 800px width screens. The main point of a fluid width was that you could have a web page that looked okay in a 1024px screen, but still could shrink down to the smaller screens still used.
Now, the trend in screens is the opposite. People are getting huge screens; 32% of people browsing Joomlashack.com are doing so with resolutions over 1440px!
With these big screens and a fluid width layout, you get a new problem—readability. Studies have shown that readability onscreen drops off as you go over 960px. So a fluid width will fill that big screen and a) look daft and b) slow down your reading.
A typical design might use tables to lay out the page. Tables are useful as a quick solution in that you just have to set the width of the columns as percentages. However, tables also have several drawbacks. For example, tables have a lot of extra code compared to CSS layouts. This leads to longer load times (which surfers don't like) and poorer performance in search engines. The code can roughly double in size, not just with markup but also with "spacer GIFs," which are 1x1 transparent images placed in each cell of the table to keep the cells from collapsing. Even big companies sometimes fall into the table trap.
There are a couple major problems with a site using tables for layout:
- They are difficult to maintain. To change something, you have to figure out what all the table tags, such as <tr> and <td>, are doing. With CSS, there are just a few lines to inspect.
- The content cannot be source ordered. Many web surfers do not see web pages on a browser. Those viewing with a text browser or screen reader read the page from the top-left corner to the bottom right. This means that they first view everything in the header and left column (for a three-column layout) before they get to the middle column, where the important stuff is located. A CSS layout, on the other hand, allows for "source-ordered" content, which means the content can be rearranged in the code/source. Perhaps your most important site visitor is Google, and it uses a screen reader for all intents and purposes.
When it comes to CSS layouts, there has been a trend toward what have been coined frameworks. The idea is that a consistent set of CSS is used to create the layout, and then that set is maintained for various issues like browser compatibility. For this template we are going to adopt the 960 grid system developed by Nathan Smith (http://960.gs/). At its most basic, your template might look as shown in Figure 9.4. It's still not very exciting, but let's look at what the different parts are all about.
Figure 9.4 Basic template layout.
In Figure 9.4, each column—left, middle, and right—is given its own element and grid size. With the 960 grid system, you merely have to specify with a class how big you want the grid to be. In this example, I am using a 12-column grid, so for the header to run across the full width of 960px, in the index.php use:
<div id="header" class="container_12">.
For our three columns, we add grids inside a container like this:
<div id="content" class="container_12"> <div id="" class="grid_3 "> <jdoc:include type="modules" name="left" /> </div> <div id="" class="grid_6"> <jdoc:include type="modules" name="breadcrumbs" /> <jdoc:include type="component" /> </div> <div id="" class="grid_3"> <jdoc:include type="modules" name="right" /> </div> </div>
Notice that there is already some breathing room to the content with a 10px column spacing, commonly called gutter. This is all automatically done by the clever 960 CSS grid framework, and all browser issues (yes, we mean you, Internet Explorer) are dealt with.
The <body> code for index.php is as follows:
<body> <div id="header" class="container_12"> <?php echo $app->getCfg('sitename');?><br /> <jdoc:include type="modules" name="top" /> </div> <div id="content" class="container_12"> <div id="sidebar" class="grid_3 "> <jdoc:include type="modules" name="left" /> </div> <div id="maincolumn" class="grid_6"> <jdoc:include type="modules" name="breadcrumbs" /> <jdoc:include type="component" /> </div> <div id="sidebar-2" class="grid_3"> <jdoc:include type="modules" name="right" /> </div> </div> <div id="footer" class="container_12"> <jdoc:include type="modules" name="footer" /> </div> <jdoc:include type="modules" name="debug" /> </body>
In this example, I renamed the CSS file to layout.css. With the 960 grid framework, we will rarely need to touch this file and can compress it as much as possible. The critical parts of the layout.css file look like this:
.container_12 { margin-left:auto; margin-right:auto; width:960px; } .alpha { margin-left:0 !important; } .omega { margin-right:0 !important; } .grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9, .grid_10,.grid_11,.grid_12,.grid_12 { display:inline; float:left; position:relative; margin-left:10px; margin-right:10px; } .container_12 .grid_1 { width:60px; } .container_12 .grid_2 { width:140px; } .container_12 .grid_3 { width:220px; } .container_12 .grid_4 { width:300px; } .container_12 .grid_5 { width:380px; } .container_12 .grid_6 { width:460px; } .container_12 .grid_7 { width:540px; } .container_12 .grid_8 { width:620px; } .container_12 .grid_9 { width:700px; } .container_12 .grid_10 { width:780px; } .container_12 .grid_11 { width:860px; } .container_12 .grid_12 { width:940px; }
Quite simply, everything is floated left, and the various grid sizes are set based on their desired width. It's a 12-column grid, so, for example grid_6 means six columns, which would be 460px—the full width minus the padding. This simple layout is a good one to use for learning about how to use CSS with Joomla because it shows two of the advantages of CSS over table-based layouts: It is less code, and it is easier to maintain.
However, this simple layout is ordered in the code in the sequence in which you see content on the screen. It is not "source ordered" to place the most important content at the beginning of the generated HTML source yet still have the same viewer-ordered appearance onscreen, with the left column displayed before (that is, to the left of) the center column.
Source-ordered layouts perform better for SEO than do layouts where the important content occurs late in the code. From a Joomla site perspective, the important content is that which comes from the mainbody component. For now, to keep the CSS simple, we'll stick with this viewer-ordered layout, and we'll change to source-ordered layout later in the chapter. Many commercial templates, for example, Joomlashack's, develop this source-ordered concept further.
Default CSS
So far, all the CSS has been only about layout, which makes a plain page. So let's add some formatting, placing the CSS in a new file called typography.css. Remember to add it to the index.php file!
As you begin working on typography with CSS, you should set some overall styles and include a simple global reset:
/*Compass Design typography css */ * { margin:0; padding:0; } h1,h2,h3,h4,h5,h6,p,blockquote,form,label,ul,ol,dl,fieldset,address { margin: 0.5em 0; } li,dd { margin-left:1em; } fieldset { padding:.5em; } body { font-size:76%; font-family:Verdana, Arial, Helvetica, sans-serif; line-height:1.3; }
The purpose of a global reset is to override the default settings that are different in every browser and get to a clean, consistent starting point, regardless of which browser the page is being displayed on. Everything is given a zero margin and padding, and then all block-level elements are given a bottom and a bottom margin. This helps achieve browser consistency. (The first CSS selector above is called the star selector, and it acts as a universal selector even in Internet Explorer 6.) You can read more about the global reset at www.clagnut.com/blog/1287/ and www.leftjustified.net/journal/2004/10/19/global-ws-reset/.
You set the font size to 76% to try to get more consistent font sizes across browsers. All font sizes are then set in ems. Setting line-height:1.3 helps readability. When you set fonts and line heights in ems, the pages are more accessible because the viewers will be able to resize the fonts to their own preferences, and the pages will reflow and remain readable. This is discussed further at www.thenoodleincident.com/tutorials/typography/template.html.
If you were to add some background colors to the header, sidebars, and content containers, you would see something like what is shown in Figure 9.5.
Figure 9.5 A basic template with typography.
Notice that the side columns do not reach the footer. This is because they extend only as far as their content; where the space is white on the left and on the right, the side columns don't exist.
If you have a template that has a white background for all three columns, this is no problem. You will use this approach and will have boxes around the modules. If you want equal-height columns that are colored or have boxes, you have to use some technique to give the columns an equal height. One common solution is to use a JavaScript script to calculate and set the heights on the fly.
Modules in Templates
When a module is called in the index.php file, there are several options for how it is displayed. The syntax is as follows:
<jdoc:include type="modules" name="location" style="option" />
The style, which is optional, is defined in templates/system/html/modules.php. Currently, the default modules.php file contains the following layout options: table, horz, xhtml, rounded, and none. Let's take a brief glimpse at the lines of code needed for each of these options:
OPTION="table" (default display) modules are displayed in a column. The following shows the output from Joomla if we use the "table" option. Note the PHP statements would be replaced by actual content:
<table cellpadding="0" cellspacing="0" class="moduletable<?php echo $params->get('moduleclass_sfx'); ?>"> <?php if ($module->showtitle != 0) : ?> <tr> <th valign="top"> <?php echo $module->title; ?> </th> </tr> <?php endif; ?> <tr> <td> <?php echo $module->content; ?> </td> </tr> </table>
OPTION="horz" makes the modules appear horizontally. Each module is output in the cell of a wrapper table. The following shows the output from Joomla if we use the "horz" option:
<table cellspacing="1" cellpadding="0" border="0" width="100%"> <tr> <td valign="top"> <?php modChrome_table($module, $params, $attribs); ?> </td> </tr> </table>
OPTION="xhtml" makes modules appear as simple div elements, with the title in an H3 tag. The following shows the output from Joomla if we use the "xhtml" option:
<div class="moduletable<?php echo $params->get('moduleclass_sfx'); ?>"> <div class="moduletable<?php echo $params->get('moduleclass_sfx'); ?>"> <?php if ($module->showtitle != 0) : ?> <h3><?php echo $module->title; ?></h3> <?php endif; ?> <?php echo $module->content; ?> </div>
OPTION="rounded" makes modules appear in a format that allows, for example, stretchable rounded corners. If $style is used, the name of the <div> changes from moduletable to module. The following shows the output from Joomla if we use the "rounded" option:
<div class="module<?php echo $params->get('moduleclass_sfx'); ?>"> <div> <div> <div> <?php if ($module->showtitle != 0) : ?> <h3><?php echo $module->title; ?></h3> <?php endif; ?> <?php echo $module->content; ?> </div> </div> </div> </div>
OPTION="none" makes modules appear as raw output containing no element and no title. Here is an example:
echo $module->content;
As you can see, the CSS options (xhtml and rounded) are much leaner in code, which makes it easier to style the web pages. I don't recommend using the options (suffixes) table (default) or horz unless absolutely needed.
If you examine the modules.php file shown earlier, you will see all these options that exist for modules. It's easy to add your own; this is part of the new templating power of Joomla 1.6.
To develop a template, you can put the module style xhtml on all your modules in index.php:
<body> <div id="header" class="container_12"> <?php echo $app->getCfg('sitename');?><br /> <jdoc:include type="modules" name="top" style="xhtml" /> </div> <div class="clear"></div> <div id="content" class="container_12"> <div id="sidebar" class="grid_3 "> <jdoc:include type="modules" name="left"style="xhtml" /> </div> <div id="maincolumn" class="grid_6"> <jdoc:include type="modules" name="breadcrumbs" style="xhtml" /> <jdoc:include type="component" /> </div> <div id="sidebar-2" class="grid_3"> <jdoc:include type="modules" name="right" style="xhtml" /> </div> </div> <div class="clear"></div> <div id="footer" class="container_12"> <jdoc:include type="modules" name="footer" style="xhtml" /> </div> <jdoc:include type="modules" name="debug" /> </body>
Let's remove the background from the layout divs and add some CSS to style the modules with a border and a background for the module titles.
We add the following to the typography. Your CSS file should now look like this:
#header{ font-size:2em; } #footer{ border-top: 1px solid #999; } a{ text-decoration:none; } a:hover{ text-decoration:underline; } h1,.componentheading{ font-size:1.7em; } h2,.contentheading{ font-size:1.5em; } h3{ font-size:1.3em; } h4{ font-size:1.2em; } h5{ font-size:1.1em; } h6{ font-size:1em; font-weight:bold; } #footer,.small,.createdate,.modifydate,.mosimage_caption{ font:0.8em Arial,Helvetica,sans-serif; color:#999; } .moduletable{ margin-bottom:1em; padding:0 10px; /*padding for inside text*/ border:1px #CCC solid; } .moduletable h3{ background:#666; color:#fff; padding:0.25em 0; text-align:center; font-size:1.1em; margin:0 -10px 0.5em -10px; /*negative padding to pull h3 back out from .moduletable padding*/ ul.actions li{ float:right; list-style:none; border:0;} ul.actions li a img{ border:0;}
Here you have added specific style rules for the modules generated with style="xhtml" and therefore generated each with a <div> of class .moduletable and having the module's heading displayed in an <h3> tag within that <div>.
The typography CSS you've created now produces the result shown in Figure 9.6.
Figure 9.6 A basic template with module and title styling.
Menus in Templates
You saw in Chapter 5, "Creating Menus and Navigation," that there are a number of settings for how a menu can be rendered.
Again, using CSS lists rather than tables results in reduced code and easier markup.
One of the other advantages of using CSS for menus is that there is a lot of sample code on various CSS developer sites. Let's look at one of them and see how it can be used.
A web page at maxdesign.com has a selection of more than 30 menus, all using the same underlying code (see www.css.maxdesign.com.au/listamatic/index.htm). It's called the Listamatic. There is a slight difference in the code that you have to change to adapt these menus to Joomla.
These list-based menus use the following general code structure:
<div id="navcontainer"> <ul id="navlist"> <li id="active"><a href=" #" id="current">Item one</a></li> <li><a href="#">Item two</a></li> <li><a href="#">Item three</a></li> <li><a href="#">Item four</a></li> <li><a href="#">Item five</a></li> </ul> </div>
This means that there is an enclosing <div> called navcontainer, and the <ul> has an id of navlist. To duplicate this effect in Joomla, you need to have some sort of enclosing <div>. You can achieve this by using module suffixes. Recall that the output of a module with style="xhtml" is as follows:
<div class="moduletable"> <h3>...Module_Title...</h3> ...Module_Content... </div>
If you add a module suffix called menu, it will get added to the moduletable class, like this:
<div class="moduletablemenu"> <h3>...Module_Title...</h3> ...Module_Content... </div>
So when choosing a menu from the Listamatic, you would need to replace the navcontainer class style in the CSS with moduletablemenu.
This use of a module class suffix is useful. It allows different-colored boxes with just a simple change of the module class suffix.
For your site, say that you want to use List 10 by Mark Newhouse (see www.css.maxdesign.com.au/listamatic/vertical10.htm). Your CSS looks like this:
.moduletablemenu{ padding:0; color: #333; margin-bottom:1em; } .moduletablemenu h3 { background:#666; color:#fff; padding:0.25em 0; text-align:center; font-size:1.1em; margin:0; border-bottom:1px solid #fff; } .moduletablemenu ul{ list-style: none; margin: 0; padding: 0; } .moduletablemenu li{ border-bottom: 1px solid #ccc; margin: 0; } .moduletablemenu li a{ display: block; padding: 3px 5px 3px 0.5em; border-left: 10px solid #333; border-right: 10px solid #9D9D9D; background-color:#666; color: #fff; text-decoration: none; } html>body .moduletablemenu li a { width: auto; } .moduletablemenu li a:hover,a#active_menu:link,a#active_menu:visited{ border-left: 10px solid #1c64d1; border-right: 10px solid #5ba3e0; background-color: #2586d7; color: #fff; }
You then need to add the module suffix menu (no underscore in this case) to any modules for menus you want styled using this set of CSS rules. This produces a menu like what's shown in Figure 9.7.
Figure 9.7 A basic template with menu styling.
Hiding Columns
So far, you have a layout such that you always have three columns, regardless of whether there is any content positioned in those columns. From the perspective of a CMS template, this is not very useful. In a static site, the content would never change, but you want to give your site administrators the ability to put content in any column, without having to worry about editing CSS layouts. You want to be able to turn off a column automatically or collapse it if there is no content to display there.
Joomla 1.6 provides an easy way to count the number of modules generating content for a particular position so that you can add some PHP testing of these counts and hide any empty columns or similar unused <div> containers and adjust the layout accordingly. This PHP if test syntax for modules is as follows:
<?php if($this->countModules('condition')) : ?> do something <?php else : ?> do something else <?php endif; ?>
There are four possible conditions. For example, let's count the number of modules in Figure 9.7. You could insert this code somewhere in index.php:
left=<?php echo $this->countModules('left');?><br /> left and right=<?php echo $this->countModules('left and right');?><br /> left or right=<?php echo $this->countModules('left or right');?><br /> left + right=<?php echo $this->countModules('left + right');?>
So if we inserted this code into our template, we might get the following results with the sample Joomla content:
- countModules('left')—This returns 3 because there are three modules on the left.
- countModules('left and right')—This returns 1 because there is a module in the left and right positions. Both tests are true (> 0).
- countModules('left or right')—This returns 1 because there is a module in the left or right position. Both tests are true (> 0).
- countModules('left + right')—This returns 4 because it adds together the modules in the left and right positions.
In this situation, you need to use the function that allows you to count the modules present in a specific location (for example, the right column). If there is no content published in the right column, you can adjust the column sizes to fill that space.
There are several ways to do this. You could put the conditional statement in the body to not show the content and then have a different style for the content, based on what columns are there. We are going to take advantage of the grid system and simply pass the sizes of the grid based on some calculations.
In the header, let's define a couple of variables to make sure they have some default value.
$leftcolgrid = "3"; $rightcolgrid = "3";
In the HTML of the template, we can then use these variables to set the grid class:
<div id="content" class="container_12"> <div id="sidebar" class="grid_<?php echo $leftcolgrid;?>"> <jdoc:include type="modules" name="left"style="xhtml" /> </div> <div id="maincolumn" class="grid_<?php echo (12-$leftcolgrid-$rightcolgrid);?>"> <jdoc:include type="modules" name="breadcrumbs" style="xhtml" /> <jdoc:include type="component" /> </div> <div id="sidebar-2" class="grid_<?php echo $rightcolgrid;?>"> <jdoc:include type="modules" name="right" style="xhtml" /> </div> </div>
You'll notice we are echoing out the colgrid values and then doing a simple calculation to find the main column, as we know they must total 12.
We then can use the countModules function to find some value. In our head we insert:
<?php if ($this->countModules('left') == 0):?> <?php $leftcolgrid = "0";?> <?php endif; ?> <?php if ($this->countModules('right') == 0):?> <?php $rightcolgrid = "0";?> <?php endif; ?>
Note that we are checking to see whether the left and right positions have zero modules as we have already set the default grid size to 3. We could have also have done this check with a true/false check rather than a numerical value (zero).
You are halfway there, but now you have expanded the width of the center column to accommodate any empty (soon to be hidden) side columns.
Hiding Module Code
When creating collapsible columns, it is good practice to set up the modules not to be generated if there is no content there. If you don't do this, the pages will have empty <div>s in them, which can lead to cross-browser issues.
To not generate an empty <div>, you use the following if statement:
<?php if($this->countModules('left')) : ?> <div id="sidebar" class="grid_<?php echo $leftcolgrid;?>"> <jdoc:include type="modules" name="left"style="xhtml" /> </div> <?php endif; ?>
When you use this code, if there is nothing published in position left, then <div id="sidebar">; also, everything within it will not be included in the generated page.
Using these techniques for the left and right columns, your index.php file now looks as follows:
<?php /** * @copyright Copyright (C) 2005 - 2010 Barrie North. * @license GPL */ defined('_JEXEC') or die; $app = JFactory::getApplication(); $leftcolgrid = "3"; $rightcolgrid = "3"; ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $this->language; ?>" lang="<?php echo $this->language; ?>" > <head> <jdoc:include type="head" /> <link rel="stylesheet" href="<?php echo $this->baseurl ?>/templates/system/css/system.css" type="text/css" /> <link rel="stylesheet" href="<?php echo $this->baseurl ?>/templates/system/css/general.css" type="text/css" /> <link rel="stylesheet" href="<?php echo $this->baseurl ?>/templates/<?php echo $this->template ?>/css/layout.css" type="text/css" /> <link rel="stylesheet" href="<?php echo $this->baseurl ?>/templates/<?php echo $this->template ?>/css/typography.css" type="text/css" /> <?php if ($this->countModules('left') == 0):?> <?php $leftcolgrid = "0";?> <?php endif; ?> <?php if ($this->countModules('right') == 0):?> <?php $rightcolgrid = "0";?> <?php endif; ?> </head> <body> <div id="header" class="container_12"> <?php echo $app->getCfg('sitename');?><br /> <jdoc:include type="modules" name="top" style="xhtml" /> </div> <div class="clear"></div> <div id="content" class="container_12"> <?php if($this->countModules('left')) : ?> <div id="sidebar" class="grid_<?php echo $leftcolgrid;?>"> <jdoc:include type="modules" name="left"style="xhtml" /> </div> <?php endif; ?> <div id="maincolumn" class="grid_<?php echo (12-$leftcolgrid-$rightcolgrid);?>"> <jdoc:include type="modules" name="breadcrumbs" style="xhtml" /> <jdoc:include type="component" /> </div> <?php if($this->countModules('right')) : ?> <div id="sidebar-2" class="grid_<?php echo $rightcolgrid;?>"> <jdoc:include type="modules" name="right" style="xhtml" /> </div> <?php endif; ?> </div> <div class="clear"></div> <div id="footer" class="container_12"> <jdoc:include type="modules" name="footer" style="xhtml" /> </div> <jdoc:include type="modules" name="debug" /> </body> </html>
The basic template created in this section shows some of the fundamental principles of creating a Joomla template.
Now that you have the basics done, you can create a slightly more attractive template, using the techniques you have learned.