CSS Tutorial
Structuring CSS
How Is CSS Rendered?
Browsers calculate declarations from the end point of the selector. Consider this declaration.
div p span {}
The browser finds all occurences of SPAN elements and then looks back up the tree to see if there is a total match, that is, if there is an ancestor of any SPAN element that is a P element, which in turn is an ancestor of a DIV element. It has been argued that such declarations (and more complex CSS3 selectors) actually hurt performance. It is further argued that a browser can more quickly apply a style if an ID or class is applied to the element.
Different blogs have published tests to demonstrate that heavy class and ID use speed up performance. But Steve Souders's tests show that optimizing your CSS by a heavy use of classes and IDs provides little in the way of actual performance gains. If Souders is correct, the only gain with writing CSS1 is that an element with a class or ID may still style correctly if moved to another context, while a more complex declaration may break. I am not entirely sure that he is correct, but I have found little in the way of poor performance. I am not prepared to confine myself to CSS1 to save a few milliseconds.
My Approach to CSS: Think XPATH
As we have said above, CSS uses the HTML document tree to match an element, attribute, or value in an HTML file. Typically, developers consider where in the visible web page they want a style to be applied. They create a style in the CSS, and then call that style into the pages wherever, and as often as, needed. If this approach could be illustrated graphically, one could imagine a CSS file and an HTML file side by side, with horizontal points of contact between them.
However, this is not the best way to understand or apply CSS. Developers should think more in vertical terms, creating paths for their styles, using CSS to snake into HTML and apply styles hierarchically and contextually rather than simply mapping a declaration to an element or elements.
To help illustrate this, let's consider XML, XPath, and XSLT. Unlike an HTML document, XML has no inherent display properties, and will appear as a series of opened branches by default when viewed in a web browser. XPath uses path expressions to navigate XML documents, and in conjunction with XSLT, transforms them into different types of files to sort and display particular elements, attributes, and values. Furthermore, in tandem with CSS or XSL-FO, styles can be applied to the transformed document. For example, using XPath, an XSLT can find every element y following an element x and display it in a certain style, e.g. bold, if its value is greater than or equal to z.
While CSS does not transform an HTML document per se—seeing that it does not possess a mechanism to perform many of the functions of XSLT—it does nevertheless navigate the DOM to apply styles to it. One may then view CSS in terms of XPath, searching through the HTML file by pattern matching, and transforming it by applying styles. By looking at the table below, you will at once see that XPath is much more powerful than CSS, especially if you are locked into CSS1, which you are confined to if you must support Internet Explorer 6. Nevertheless, we will argue that writing CSS in this fashion will yield better results in the form of more intelligently crafted CSS. It is more a matter of methodology than technology.
| XPath | CSS | Notes |
|---|---|---|
| //movie - finds all elements named "movie" | P - finds all elements named P | Support in CSS1 |
| //movie//title - finds every element "movie" that has a descendant element "title" | div p - finds all DIV elements with a descendant P element | Support in CSS1 |
| //movie/title - finds every element "movie" that has a child element "title" | div > p - finds all DIV elements with a child P element | Support in CSS2.1 |
| //movie[@lang] - finds every element "movie" with attribute "lang" | div[title] - finds every DIV element with a title attribute | Support in CSS2.1 |
| /movie/dvd[price=10] - selects all "dvd" elements of the "movie" element that have a price (value) element with a value of 10 | div[title="Hello"] - finds every DIV element with a title attribute value of "Hello" | Support in CSS2.1 |
| /movie/dvd[price>10]/title - selects all the "title" elements of the "dvd" elements of the "movie" element that have a price greater than 10 | CSS3 can test for a specific value using the value pseudo-element, but cannot perform comparisons. | No CSS equivalent |
Now, our analogy breaks down a little again when we consider that while XML has no inherent display properties, HTML does. Though style and content are entirely separate between XML and XSL-FO, one can only approximate such a separation with HTML and CSS. A P element in an HTML document, for example, formats by default in a certain way depending upon the User Agent (UA). Some or all of the default formatting inherent in a UA's display of a paragraph might be maintained with little intrusion from CSS. But the P element also gives meaning to the document by separating units of thought. Thus the unadorned P element conveys both content and style. One could also argue that elements like CITE and BLOCKQUOTE are content. They also have a default style depending upon the user agent. We are not advocating that all styles be separated from the HTML by converting all tags to DIV or SPAN elements. Semantic diversity, which we will introduce below, will actually aid in CSS development.
If we then accept this somewhat artificial definition of content, we can still say that an HTML document contains content (in the form of text, images, and to some extent, in the HTML elements themselves), and that styles which are not native to the tags themselves are defined in the CSS. Ideally, a webpage consists of well-formed, valid, and semantically-rich HTML markup that links to (or imports) CSS, that in turn styles the HTML with minimal added hooks from within the HTML. Indeed, CSS and HTML should be separated to the degree that one should have few immediate clues as to how the page is to be formatted after studying the document view source.
Defining Basic Elements
In this section you will get a little hands-on experience with CSS. It is designed to help you structure, organize, and economize your CSS. First start with a blank file and enter the universal selector. Use it to neutralize the padding and margin inherent in HTML tags such as <p>. This will give you greater control, and separate styles from HTML. As we said above, HTML tags should structure the content rather than style it.
* {margin: 0; padding: 0;}
Sometimes this is too heavy-handed, and needs to be less inclusive. Starting off a CSS as follows might be more advisable.
ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,body,html,p,blockquote,fieldset,input {margin: 0; padding: 0;}
Or if you are using HTML5 you might try a variant of this.
html, body, div, span, h1, h2, h3, h4, h5, h6, p, blockquote, a, abbr, address, cite, code, del, dfn, em,
img, ins, q, samp, strong, sub, sup, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption,
tbody, tfoot, thead, tr, th, td, article, aside, audio, canvas, details, figcaption, figure, footer, header,
hgroup, mark, menu, meter, nav, output, progress, section, summary, time {
margin: 0; padding: 0; border: 0; outline: 0; vertical-align: baseline; background: transparent;
}
Eric Meyer has taken this concept to a noteworthy degree.
On the other hand, it might be reasoned that nullifying all styles and then resetting them is a waste of code and processing time. Jonathan snook declines using a reset.
Next, define the BODY element, making sure to add the background color, because UAs may default to a gray background. Here is a partial sample.
body {margin: 0 auto; background-color #FFF; font: 62.5% Verdana, Arial, sans-serif;}
Another approach (as mentioned above) is to set font size in the HTML element using a percentage and then set the body element to 1em, or whatever base size you want.
html {font-size: 70%;}
body {margin: 0 auto; background-color #FFF; font: 1em Verdana, Arial, sans-serif;}
By the way, the margin setting above will center your page within the browser, which is usually desirable.
Since the border attribute is deprecated for images in XHTML, we need to neutralize that attribute as well.
img {border: 0 none;}
Let's now start setting up our link colors. We first define the "default" colors in LoVeHAte order.
a:link {color: blue;}
a:visited {color: gray;}
a:hover {color: blue;}
a:active {color: red;}
We will likely want to override these colors in some contexts, but they will suffice for now.
Next define all the elements you are going to use and group together those that are similarly defined. You can stack up similar styles by comma-delimiting them. Then you can define other aspects of those elements individually.
h1, h2, h3, p {font-family: "Trebuchet MS", Verdana, sans-serif;}
h1 {font-size: 1em; line-height: 1.7em;}
h2 {font-size: 0.9em; line-height: 1.5em;}
h3 {font-size: 0.8em; line-height: 1.4em;}
p {font-size: 0.7em; line-height: 1.2em;}
Note that in the first line above the styles apply to each of the four elements because they are comma-delimited. That is, the statement calls a list of simple selectors. Without the commas the elements would be in a descendant relationship. If you wish to have a DIV element and a SPAN element behave the same within the header ID, invoke the properties as follows:
#header div, #header span {font-weight: bold;}
not
#header div, span {font-weight: bold;}
Next define basic classes, many of which you will override in certain contexts. After that define your context-specific IDs, which we discuss in the next section.
Be careful. If your browser finds a critical error when it parses a line in your CSS file, it may ignore the entire declaration.