Which sections will require containers (divs)?
<ul><body>, so an outer wrap is needed.
Now that we've planned out how we are going to make the design a reality, it's time to get get your hands dirty.
The first thing that needs to be added to our basic XHTML shell is our (empty) CSS file.
How will we import our CSS? That decision is guided by our intended browser support. Since we don't want to send any CSS to Netscape 4 or IE mac, we will use the following @import method...
<style type="text/css" media="screen,projection">
/* backslash hack hides from IEmac \*/
@import url(default.css);
/* end hack */
</style>
By setting the media attribute to screen,projection (note comma seperated list — do not add a space), we are locking out NN4 and also telling Opera to use this style sheet in projection mode (full-screen mode).
Because we don't want to feed IE/mac a style sheet which it cant handle, we include the ‘backslash hack’ to send that browser on its merry way.
Now we are serving our CSS to all intended browsers, while legacy browsers are left with unstyled mark-up.
Those who have read my article on this subject would know that I prefer to keep all IE specific hacks in an external file and reference that file via conditional comments. For this project, however, we will be retaining all IE hacks (valid hacks!) in the main CSS file to keep down the number of server requests per visitor.
I mentioned previously that we will use a wrapper div to hold our design together, but this div also fills a much more important role &mdash it will control the scaling of the design.
% or em? BOTH!In an ideal world, our design would expand and contract to fit within the available screen real-estate while still maintaining a legible line-length regardless of font-size or resolution.
He's gone mad with power!
Not at all (well, maybe a little); this utopian goal is achievable — even in IE5!
div#outer {
width:94%;
min-width:40em;
max-width:70em;
}
By combining a percentage width with em min. and max. widths, we can be assured of the following:
70em, keeping line lengths manageable.em is a relative unit and is controlled by the user, font-size will always take precedance over screen-width for deciding the width of the layout. If a user with a res. of 800x600 increases their font-size to 'xx-large', the design will expand and cause horizontal scroll. Is this a Good Thing™? I believe so.min/max-width, so we will employ a great little script to add that functionality. Whilst it is far from best practice to use javascript for layout purposes, the page will still function like any other fluid-width design sans-script.There are three properties I set at the beginning of every style sheet; padding, margins and a base font-size.
My preferred method is to globally reset all margins and padding to zero and assign them to elements as needed. I prefer this over instances of margin:0;padding:0; all through my CSS and I have repeatedly found it to cut the development time required for CSS layouts.
For font sizing, I use the method of setting a base size for the body element and em for all other elements, starting at 1em for the content text. For more information regarding the issues relating to even font-scaling, take a look at this.
* {
margin:0;
padding:0;
}
body {font-size:90%;}
The reason the font-size property is not declared within the global ruleset is that it has undesirable affects in relation to nested elements — the deeper you go, the smaller they get!
There is one part of styling links that many fail to remeber — hovering with a mouse is not the only method of focusing on a link. Many users, myself included, use the tab key to skip through links on a page. To accomodate these users, we add a visual cue to the :focus pseudo-class.
Once again, IE/PC comes to the party and leaves a horrid mess; in this instance the problem is that IE does not render the :focus pseudo-class, but it does treat :active as :focus
Here's our basic link styles, with the :focus and :active pseudo-classes added:
a {
color:#4C53E0;
}
a:focus, a:hover, a:active {
color:#EB8518;
}
If you have trouble remembering the order for these declarations; this lymeric is a great help:Lord Vader's Former Handle, Aniken
Time to get serious — our designer has presented us with a design that contains a fluid-width banner with vertically centered text. Since we can't use the v-align attribute in XHTML, we'll use line-height to achieve the same effect.
<div id="header">
<h1>GeneriCo.</h1>
</div>
#header {
background:#EBEBE9 url(img/banner-bg.jpg) repeat-x left bottom;
}
#header h1 {
font:bold 3em/2.5 "Lucida Bright", Georgia, Times, serif;
background: transparent url(img/banner.jpg) no-repeat right bottom;
}
By using line-height to achieve even vertical padding and attaching our non-repeating image (the buildings) to the bottom right corner of the h1, we have reliable vertical spacing and image placement regardless of font-size. Get used to that term, I love anything that works regardless of font-size
.
The design for the menu is reasonably simple, so I won't go into excessive detail.
Here is the basic CSS:
ul#nav {
list-style:none;
text-align:center;
background:#fff;
}
#nav li {
width:25%;
float:left;
display:block;
text-align:center;
background:#EAF0E6 url(img/mnu-btm.gif) repeat-x left bottom;
}
#nav a {
display:block;
font:bold 1em/1.8 'Lucida Grande', Arial, tahoma, verdana, sans-serif;
text-decoration:none;
background:transparent url(img/mnu-top.gif) repeat-x left top;
}
Each of the four menu items is assigned a width of 25% and floated, causing them to line up horizontally. To create the button effect in from the intial design, two small gradient images are tiled along the x-axis of the link and its parent li. Once again, line-height is employed for the purpose of vertical alignment.
As we discussed earlier, to place our content in the optimal position within the source (ie: as early as possible) we will need to add an extra div (hereby known as #sub), which wil be floated to the left. The first div within #sub will be floated right and will then sit in the center of the comlete layout.
Our design dictates the following widths for the columns:
#left: 25%#center: 50%#right: 25%Simple, right? Not quite — because of our newly aquired #sub wrapper, we have to calculate the widths of #left and #center according to their parent element.
#sub: 75%#left: 33%#center: 66%#right: 25%While it may seem confusing at first, it's actually pretty straight forward. Our #sub wrap takes up 75% percent of our content area. Within, #center takes up 66% of it's parent (#sub), which translates to 50% of our content area. #left fills the remaining 33% of #sub and #right is assigned a width of 25% due to the fact it is not nested within #sub, so it's width is calculated accroding to our entire content area.
To avoid the need for box-mdel hacks (which become nightmare-ish when dealing with this sort of layout), I have reduced the width of each column slightly, using the remaining gaps between them as the column ‘gutters’
Now that we've got three well-proportioned columns, it's time to fill them up with content. The main point I want to make regarding content is in relation to units of measure for padding and margins.
The best way to achieve a consistant design regardless of resolution or font size is by using percentage values for all horizontal spacing and em for all vertical spacing.
Here is a simple example:
p { margin:1em 5%; }
By default, web text is rather messy. The leading (line-spacing) is tiny and the words are crammed together in an unappealing manor. Here's how we fix that:
#sub, #right {
font: 1em/1.5 'Lucida Grande', arial, verdana, sans-serif;
word-spacing: 0.1em;
By defining our word-spacing in em, we are assured of consistency regardless of font size.
The left column contains an image which our designer assures us draws the eye towards the 'Catalogue' link in the menu.
We think he's had one too many lattes, but we'll keep him happy anyway.
This image is assigned as the background for #left and is anchored to the top right corner.
To overcome the problem of 'running out of image' as the column expands vertically, we asked our designer to make up a version of the image which fade to white at the left edge. While the gradient can often be less than ideal visually, I find this approach to be good balance between having 'image to spare' and saving every bit of bandwidth. A vertical example of this technique can be found in the banner I made for brothercake.com
Forms provide a wealth of styling hooks without extraneous mark-up, so that isn't a concern. What is a concern is the width of the input elements. Once again, our simple rule of setting all horizontal measures using % saves the day.
To make maximum use of the space available, we will assign a width of 98% to the text inputs, with the extra 2% allowing for padding within the form.
To differentiate between various input types, we have to add a class attribute (.txt in this case) — this will not be necessary once all common browsers support the full CSS2 selector set.
The ideal method of differentiating between input types would be to use attribute selectors:
input[type=text] { /* text input styles */ }
input[type=submit] { /* submit input styles */ }
The footer is a simple affair, with a horizontal menu and a short copyright notice.
Contrary to the main navigation, the footer nav. uses inline lis to minimise the horizontal space required. Because we don't add presentaional mark-up, the 'pipe seperator' is emulated using a CSS border.
Here is the CSS for the footer menu
#footer ul {
list-style:none;
margin-top:0.7em;
}
#footer li {
display:inline;
border-right: 1px solid #C8DCC2;
padding:.3em 2%;
}
Although this breaks our strict grid layout, it also reduces the probability of the copyright notice causing the menu to line break.
Semantic XHTML is thing of beauty, perhaps; but a dash of unobtrusive javascript is a great way to tip the usability scales in your favour.
Text inputs often contain examples of intended input or further instructions relating to the field. This used to be required due to early browsers having issues with empty input elements.
A common addition to pre-filled input elements is this.select() attached to the onfocus event — this causes all text within the field to be selected upon focus of the element, allowing the user to start typing immediately without first deleting the existing content.
If javascript is disabled, the user will need to first delete the existing content, so why don't we use javascript to add it in the first place?
This script will do exactly what we're after — add the filler text and also attach the onfocus behaviour.
function prepInput( id , text ) {
//check that getElementById is supported and element exists
if (!document.getElementById(id)) { return false; }
var elem = document.getElementById(id);
elem.setAttribute('value', text);
elem.onfocus = function() {
this.select();
}
}
To call the function, we add this script block to the head of the page:
<script type="text/javascript">
// <![CDATA[
window.onload = function() {
prepInput('searchQ', 'Enter search term');
prepInput('subEmail', 'you@youraddress.com');
}
// ]]>
</script>
But we can take this one step further...
Another nice usablilty feature of CSS is the ability to add styling chages for currently focused form elements using the :focus pseudo-class. IE, of course, can't cope with such advanced CSS (bahaha!), but we can make it obey our commands by addinga few lines to the existing script
function prepInput( id,text ) {
if (!document.getElementById(id)) { return false; }
var elem = document.getElementById(id);
elem.setAttribute('value', text);
// store class name
var origClass = elem.className;
elem.onfocus = function() {
// append 'focus' to class, emulates :focus pseudo-class for IE
this.className += " focus";
this.select();
}
// return class name to origClass after element loses focus
elem.onblur = function() {
this.className = origClass;
}
}
Then in our CSS, we have this:
input:focus, input.focus { border-style:inset; }
Check it out: GeneriCo.
So it's fluid, it's elastic, it's simple and it works. Did we miss anything, or have we met all our goals?
We've written clean, accessible code, we've made a flexible layout that will accomodate any combination of resolution and font size, so I guess we get the WAI-AAA stamp of approval...
There's one crucial element that our designer overlooked, one which we then also overlooked — contrast.
There isn't sufficient contrast between the content header anxc the white background, or between the menu text and its background.
Accessible code does not equal accessible design.
For more details on specific sections of the CSS, XHTML and Javascript, please refer to the source code. It is heavily commented and includes URLs of further reading.