CSS Tutorial
Contextual CSS
Now we want to divide our pages into logical areas, and reflect those pieces as CSS IDs. So what's the difference between a CSS ID and a CSS class? They do much the same thing but classes apply to repeat items, while IDs apply to items unique to a page. It's more a question of structure than technology, though IDs have greater weight. IDs promote thinking of your pages in terms of definable content areas. IDs are declared in CSS with a preceding hash sign. The idea is to add enough IDs to provide general hooks for your CSS, without getting too granular.
Here is an abbreviated example. We start by creating the basic structure of the page. Note that the "outerWrap" ID envelops the entire page. Note also that the "mainNav", "main", and "adPanel" IDs all have their float properties set to "left". This means that they will sit side by side even though DIV elements have a block display value. The "header" and "footer" IDs both have a clear property set to "both" so that they will not share their horizontal plane with any other ID.
Use CSS comments to demarcate your declarations. Comments start with "/*" and end with "*/", and can span more than one line. Using interCaps (camel case) for classnames and IDs is recommended.
/* IDs */
#outerWrap {width: 100%; margin: 0 auto; text-align: left; border: 1px solid #000;}
#header {width: 100%;}
#mainNav {width: 20%; float: left; border-right: 1px solid #666;}
#main { width: 59%; float: left; text-align: center;}
#adPanel {width: 20%; float: left; border-left: 1px solid #666;}
#footer {clear: both; width: 100%}
I have left out padding from these components, but chances are you will want to add it so that content does not sit at the edge of its container. We can now develop an HTML shell.
<!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="en-us" lang="en-us">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>title</title>
<link href="/css/main.css" rel="stylesheet" media="screen" type="text/css" />
</head>
<body>
<div id="outerWrap">
<div id="header"></div>
<div id="mainNav"></div>
<div id="cart"></div>
<div id="adPanel"></div>
<div id="footer"></div>
</div>
</body>
</html>
Let's analyze our CSS. The "outerWrap" ID sets the page width and places a border around everything. The margin set to "auto" will center the entire page. It's a neat little trick to center the page within the viewport, but not the content in it. Next we use the float property to lay the "mainNav", "main", and "adPanel" IDs side by side. The footer, like the header, is for the time being left mostly undefined.
Now, before filling your CSS up with classes, you should start defining elements within the IDs. Let's suppose that the links in the style sheet that we just defined are only for the main area, and that we want to define links in the header as red on a white background, but make links in the footer white on a black background. You might create two classes and apply them to all of the anchor tags. But that is unnecessary as it adds to maintenance and document weight. It also would not address what to do with hover, visited, and active states. A better approach is to define anchor tags within separate contexts.
#header {background-color: #FFF;}
#header a {color: #F00;}
#footer {background-color: #000;}
#footer a {color: #FFF;}
See how easy that is? Not a single class has been created. This is the power of descendant selectors, or what I call more broadly, contextual CSS. Note also that we have not so much as touched the HTML, except to insert our DIV elements as IDs. Contextual styles result in clear HTML. The footer, for example, might look like this:
<div id="footer">
<ul>
<li><a href="#">client services</a></li>
<li><a href="#">store events & locator</a></li>
<li><a href="#">faqs</a></li>
<li><a href="#">about</a></li>
</ul>
<ul>
<li><a href="#">site map</a></li>
<li><a href="#">corporate governance</a></li>
<li><a href="#">terms of use</a></li>
<li><a href="#">security & Privacy</a></li>
</ul>
</div>
Expanding upon the previous example, the CSS used to style this footer might be:
#footer {width: auto; margin-top: 40px; padding: 0 6px; font-size: 11px; text-align: left;
color: #999; background-color: #000;}
#footer a {background-color: #000; color: #CCC; text-decoration: none;}
#footer ul {list-style-type: none; padding: 0;}
#footer li {display: inline; padding: 0 3px;}
Note that the CSS first defines the footer as a whole, and then the anchor tags within the footer. Then each row within the footer utilizing the UL element is defined, since we have two rows. Lastly, each individual list item is defined. (We defined anchors separately because anchor tags do not inherit the color of their container tag.) Note also the flexibility of using an unordered list horizontally and without bullets. This use is perfectly legitimate because the footer functions as a list even though it lacks bullets or numbers. This raises an interesting point. HTML should use semantically-relevant tags. Otherwise most of your page will be nested DIVs, which are technically correct, but bewildering to track. There are other benefits to diversifying your HTML elements, which we will discuss below.
Another enormous advantage of contextual CSS relates to maintenance. Imagine you are a developer and you wish to make some text bold, or nudge it a little. Instead of studying a 1600 line CSS file to find an appropriate class (or worse still, creating a new one), you can simply go to the appropriate ID in the style sheet and hunt there. Are you working on the shopping cart? Look for the "cart" ID in the CSS, and see what is defined there. Try to add styles that do not create a new class if possible. But if you do create a new class, define it within that context. For example, if you need all the text italicized in the header of the cart, don't make an "italic" class; simply add this to the CSS.
#cart th {font-style: italic;}
This ensures that you do not interfere with the display of any other table headers.
This seems like a good place to provide a valuable hint. Generally you will want content to breathe a bit in its container. It is best to use padding on that container rather than using margins or padding on every element within that container. This will save you some electrons. But what if you want some elements to be flush to the container? You can assign negative left and right margins to any element that needs to be flush in order to extend it to the edge of the container. This in effect cancels its padding.
#container {padding: 10px;}
p.exception {margin: 0 -10px;} /* the element you want flush */
You cannot, however, assign negative padding.
Classes
As we have said before, classes are reusable, while IDs are unique to a page. We use IDs to drill down into the DOM so as to avoid class use as much as possible. However, creating classes is still pretty much unavoidable even with contextual IDs because the more advanced aspects of CSS are not yet supported by all the major browsers. So let's learn how to use classes properly. Create classes in your CSS by preceding them with a period. Common ubiquitous classes can be defined in a separate block in your CSS and placed, for example, above your ID declarations. It is advisable to specify classes that are unique to the context of a particular ID or a particular element separately. Here are three examples.
.cartHeading /* put these first two more general classes in one place */
p.cartHeading
#upperCart div.cartHeading /* put this class with other #upperCart declarations */
You should not name classes by how they style, like "tenpxBoldRed", but by the purpose they serve, like "shoppingCartHeader", "buyBox", "helpBubbleBody". The advantage to the second method is that if the style changes for your shopping cart header, you will not have to worry about disturbing other contexts, and you will not have to edit the HTML. If you have more than one Web Developer, you may assign a CSS gatekeeper to enforce ID and class creation as well as nomenclature.
Class and ID Combinations
Imagine you have a table that displays the items in a cart. (Tabular display, such as that in a cart, is a legitimate use of HTML tables.) Let's assume that all cells should be center aligned except for one.
table.cartTable td {text-align: center; padding: 8px 0;}
table.cartTable td.qty {text-align: left; padding-left: 6px;}
In the example above you define the class "cartTable", which will go in the table element. The "cartTable" class, along with the descendant selector specifies that all cells within that table will be center-aligned. In the next line you create a class "qty" to handle an exception, which will go in the appropriate TD element. So this table will have two classes in it. That's not bad. Since this will likely be iterated by the backend, you are only going to actually type the second class once.
Or better yet you could give the table an ID.
table#cartTable td {text-align: center; padding: 8px 0;}
table#cartTable td.qty {text-align: left; padding-left: 6px;}
We will return to this table in this manual as we introduce you to more powerful CSS techniques. We will even find ways to avoid the use of the "qty" class above to more cleanly separate the CSS from the XHTML.
Multiple Class Conjoining and Class-ID Conjoining
Classes can be used in complex ways. Multiple, space-delimited classes can be applied to one HTML tag. Precedence will be given to the class that is located farther down within the CSS file, that is, with the greatest weight—not by being placed last in the tag's class attribute. In the following example the text should be yellow. (No, these are not good classnames, but we are illustrating a point.)
CSS:
.blue {color: blue;}
.yellow {color: yellow;}
HTML:
<p class="yellow blue">Some text</p>
Classes can be conjoined in the CSS without white space between the classnames, which gives them a higher precedence when used together. In the following example the color green will be applied to any element that has space-delimited classes that list both "blue" and "yellow" in either order, with or without other classes.
CSS:
.blue {color: blue;}
.yellow {color: yellow;}
.blue.yellow {color: green;}
HTML:
<p class="blue someOtherClass yellow maybeAnotherClassHere">Some green text</p>
Conjoining classes removes the descendant relationship between the classes, and enforces the style if the classes are siblings applied to the same element.
Note: IE6 only recognizes the last class in such a conjoined declaration, though it may not be immediately apparent. Let's re-consider our last example:
CSS:
.blue {color: blue;}
.yellow {color: yellow;}
.blue.yellow {color: green;}
HTML:
<div class="blue">this should be blue</div>
<div class="yellow">this should be yellow</div>
<div class="blue yellow">this should be green</div>
A compliant browser will correctly render these lines. However, after IE6 correctly renders the first line blue, it then renders both remaining lines green. Here's why. IE6 correctly applies the color yellow to the class "yellow". But when it reads the third declaration, "blue.yellow", it can only see ".yellow", and thus re-defines the "yellow" class to be blue. Again, IE6 will let you apply multiple classes to an element, but it will not let you define how two classes behave when conjoined. This is confusing because the first time you see the effects of the conjoined classes in IE6, you may not notice that IE6 does not support it. You will only notice a problem after you observe that IE6 has re-written the "yellow" class. My recommendation is not to use conjoined classes directed at IE6.
But for all that, CSS gives you a lot of control—at least with compliant browsers—even to the point of increasing the specificity and weight of classes. Fortunately, IE6 will allow you to conjoin an ID and a class, though, of course, you can only legally use the same ID once per page. This is useful in one instance. Let's suppose that you have a default class that you use a lot. Let's further suppose that you want to override that class within a certain context.
.xyz {color: blue;}
#abc .xyz {color: yellow;}
Within the context of the ID "abc", the "xyz" class will render yellow. However, there may be times when you do not have enough control over the context of an element, that is, you cannot add a wrapping element in the markup. In this case you can add context to it, so to speak, by adding an ID, and conjoining the ID and the class in your CSS. The removal of the space between classes—or between an ID and a class—in effect removes the descendant relationship between classes. Without the space—which as we learned above is the descendant combinator—the classes (or ID and class) retain a sibling relationship.
CSS:
.xyz {color: blue;}
#abc.xyz {color: yellow;}
HTML:
<div id="abc" class="xyz">text</div>
Again, by declaring the ID and the class without a space in between them, we have created a sibling rather than a descendant relationship between the two.
Semantic Diversity
Sometimes when developers make the switch to CSS layout they simply start using the DIV element in place of the TD element. However, HTML does have a fairly rich arsenal of tags, especially HTML5, which includes elements such as HEADER, NAV, FOOTER, SECTION, ARTICLE, FIGURE, FIGCAPTION, ASIDE, etc. We already said above that a list of links in a footer could well be placed in an unordered list. A list of recent purchases is perhaps best put in a data table. An address could be placed in the overlooked ADDRESS element. Forms should make use of the FIELDSET and LEGEND elements. Using alternative tags makes your HTML documents more rich semantically, and more accessible. A screen reader, for example, will read the LEGEND element before each label associated with radio buttons (if they are all within the same FIELDSET element). This helps the user with a visual disability to better understand the document. Semantic diversity also helps with the use of CSS. Let's suppose you want to use headings in your forms. You could add markup and CSS like this:
CSS:
.formHeading {color: blue;}
HTML:
<div class="formHeading">text</div>
Or you could ditch the DIV element and use the more correct LEGEND element. Then you would not have to go back into the HTML to add a class.
CSS:
legend {color: blue;}
HTML:
<legend>text</legend>
Semantic diversity also helps with search engine optimization (SEO) in that text in, say, an H1 element, may be weighted differently from text in a P element. But SEO is beyond the scope of this document.