jorvis AT users.sf.net

presentation using cascading style sheets (CSS) - introduction

a tiny bit of history

Cascading Style Sheets (CSS) have actually been around for longer than most people think. Developed together by Håkon Wium Lie and Bert Bos, CSS were initially proposed in 1994 and finally recommended by the W3C in late 1996 (CSS1). Only the especially brave used it until 1999 though, when the first browser finally implemented (nearly) all of the features given in the CSS1 specification. Naturally, by that time the CSS2 specification had already been defined by the W3C. The current spec is CSS2.1, though CSS3 development has been underway since 1998.

The "cascading" part of CSS refers to the fact that any given element obtain its style rules from multiple sources. The specification provides a series of inheritance and weighting rules so the browser can choose the right rule. You can, for example, specify rules for the same element in multiple places and a series of precedence checks define which rule should apply.

why use it?

ESPN.com redesign

  • est. page reduction: 50kb
  • page views/day: 40,000,000
  • bandwidth savings: 730TB/year

There are a myriad of sites and book chapters which discuss the benefits of CSS in great detail but they all can by summarized these: it makes development easier, saves time and saves money. Throughout this tutorial I hope to demonstrate the benefit of the logical separation of style from content. For now, here's a real-world example.

The ESPN.com CSS redesign is a great example of a large commercial site recognizing the benefits of CSS. By re-coding their pages to adhere to more strict markup rules and shifting the burden of styling to CSS they trimmed the average size of each page by 50 kilobytes. That may not sound like much, but it means less manual coding and code generation has to happen on the server side and less data needs to be pushed to the client's browser. This means pages load faster and ESPN.com saves a lot of bandwidth. When you serve as many pages as they do, this means saving millions per year.

As described in an interview with Mike Davidson, ESPN.com serves over a billion pages per month. By cutting their average page size they saved an estimated 730 terabytes of bandwidth per year! Of course, file size reduction was not the only reason ESPN.com performed the migration. The newer, modular design will simplify future development and enable display on new portable devices such as phones, PDAs and other portable viewers.

where does it go?

There are two primary ways you can add stylesheet information to your document - either directly within your HTML or contained in an external file. We'll first give examples of both, so you know where to put your CSS rules, then we'll learn the syntax of the rules themselves.

embedding CSS within your document

An easy method for adding CSS information within your HTML document is to add a <style> element within the header and type it right there. The general form is like this:

<style type="text/css"> css rules here </style>

If you know that your style information is going to be minimal and/or it doesn't apply to multiple pages this is an acceptable way to define your style information. If, on the other hand, you are going to have a multi-page website and the pages will share common style rules, this probably isn't the best way to go. By embedding style information directly in your page you are likely to copy the same rules onto each page. Then, if you want to change the way something looks across your entire site, you'll have to go and change each of those embedded stylesheets. Linking to an external stylesheet would be a better solution.

linking to an external stylesheet

Still within the page's <head> element, you can put a pointer to a CSS file rather than embedding it directly in the document. This way many different HTML files can just reference a particular stylesheet, and any changes made to that stylesheet will be reflected immediately upon any HTML pages that reference it. The general syntax for referencing an external stylesheet is:

<link rel='stylesheet' type='text/css' href='/path/to/some_file.css'>

styling an element directly

I said there were two primary ways for adding style to your document, which is true, but there is one other way that is less encouraged. You can actually embed the style for a given element directly as that element's attribute, like this:

<div style='border: 1px solid rgb(0,0,0)'> some text here </div>

The declaration above forces a div element a 1 pixel solid black border. This sort of direct styling is discouraged because we would be right back to embedding presentational content directly within your HTML, losing all the modularity and flexibility that the separation of content and presentation affords us. If you absolutely must do it though, the capability is there.

what does it look like?

Whether you put your rules inside your HTML documents or in external files the method of coding the CSS rules is the same. Each rule is composed of two parts: a selector and a declaration block. The declaration block contains any number of CSS declarations, which each consist of property / value pairs. These pairs are separated with a colon (:) and each declaration ends with a semi-colon (;). Let's see an example:

p { font-weight: bold; background-color: rgb(0,200,0); }

This simple rule's selector is simply a p (paragraph) element and contains two declarations. In english, it says "for all paragraphs make the font bold and have a blue background." Learning the available properties is simply a matter of memorization (or the use of a good cheat sheet. Learning to master the use of selectors, on the other hand, involves learning a few conceptual rules.

CSS selectors

Selectors are used to define which elements you wish to style. At the very basic level you can easily access elements by their name (such as 'div' or 'table'). This would make CSS useful but not very powerful. We really need to be able to access elements by their class or id. Finally, we want to also be able to access elements based on their parent, child or adjacent elements. We'll give examples of each of these in turn, noting those that are not supported across most browsers.

type selectors

div { color: rgb(0,0,0); }

Type selectors are the most simple. They simply apply to all elements of the type specified (a <div> in this case).

universal selector

* { font: small verdana, sans-serif; }

I've never really had much use for this one, but using an asterisk as the selector you can set a declaration for all elements of the page. Here, for example, I set a global font.

ID selectors

#friend_list { list-style-type: square; } or ul#friend_list { list-style-type: square; }

Elements can be referenced by their id attributes using the '#' symbol. There are two ways to do this, using just the id portion (#friend_list) or by naming the element type and its id (ul#friend_list). This is the most specific way to reference an element, since only one element on the same page can have a given id.

class selectors

.organism { font-style: italic; } or span.organism { font-style: italic; }

When you want to refer to elements of a specific class, your CSS selector is formed using a dot (.) followed by the class name. The upper rule, for example, defines that the text for all elements of class 'organism' should be rendered in an italic font. If you want to narrow this down to only specific element types of a certain class you can use the element type first such as in the second example, which makes the font italic only for all span elements of class 'organism'.

descendant selectors

Descendent selectors allow the user to utilize the tree structure of HTML and specify which elements they want to style based on their parent elements. If we have the following markup:

<div> <p class='latin'> Si denuo congeles, confestim ibis in fossam purgamentorum. </p> <p class='spanish'> Vamos a jugar al basketbol. </p> </div>

We can use the following rule to access only those latin paragraphs that are contained within a div:

div p.latin { font-weight: bold; }

You can reference elements as deep in the tree as you like. Any space you put between elements within the selector simply means that the element on the right must be contained within (or a descendant of) the element on the left. Note that the descendant selector will catch all descendants of a certain element, not only those that are direct children.

child selectors

If you only want to reference direct children of another element you can use a child selector. This is similar to the descendant selector above, except it does not traverse the tree. If we use the same example as above, but use a child selector we would have:

div > p.latin { font-weight: bold; }

Instead of a space between elements of the selector the > symbol is used. Warning: this selector type is not supported by Internet Explorer 4, 5, or 6.

adjacent sibling selectors

There are some occasions where you want to select elements based on their next neighbor (known as an adjacent sibling) rather than parent or child. This is accomplished using the plus (+) symbol:

h1 + h2 { margin: 2px; }

This will style any <h2> element that is directly preceeded by a <h1> element. Warning: this selector type is not supported by Internet Explorer 4, 5, or 6.

A few other selectors are available but not discussed here because of their weak browser support. For more information, see this excellent CSS selector resource.

the CSS box model

box model resource

For a great discussion of the css box model see this site, which is also the source of the image used here.

Before we move on to styling our complete example document, we need to cover what is known as the CSS box model. Because all elements can be thought of as little boxes and we can use CSS to style parts of those boxes such as size, padding, margin, etc., we need to know how each of those things are structured within the elemental box.

box model diagram

At the core of the box model you have what is called the content container. When you define the size of an element, this is the part you are sizing. Just outside of the content container you can define padding. Just outside of that any border will appear, and just outside that is the box's margin.

Those not familiar with the box model will commonly make sizing mistakes. If, for example, you size a <div> element to be 300px wide but then add a 10px margin and 5px padding, your box will now actually take up 330px of the width of the page. This is because the margin, padding and border properties of the box are added to the height and width of the box, not part of it.

If you assign a background color or image to this div, it will appear behind both the content container and any padding area, but not the margin.

This is a pretty direct definition of how the parts of a box should be rendered, and one might suppose that the different browser vendors would be able to get so small a set of rules implemented correctly. As it happens, one would presume too much. While most modern browsers all do it correctly (Firefox, Opera 6 and 7, Netscape 7, Mozilla, Safari, Camino and IE 5 for Mac), others muck it up (can you guess which?).

Internet Explorer 6 will get it correct only if you specify a DOCTYPE that references a valid dtd (as each of the DOCTYPES we discussed earlier do.) If you omit the DOCTYPE, or use IE 4 or 5, the width of the box is not just the content area but also includes the borders and padding. This causes all boxes in these versions of IE to be smaller than they are in other browsers. Though they are ugly, quirks in different browers are often handled by taking advantage of CSS parsing differences between them, also known as CSS hacks.

CSS hacks

centricle hack list

The centricle site lists more css hacks than you probably wanted to know existed. They are presented in an informative grid format that makes it easy to see which browers and versions are affected by each hack.

Even though standards exist it's quite clear that not all browsers follow them. While it can be argued that you shouldn't expect to be able to control every visual element of your page across all browsers (pixel-perfect design), you'll occasionally need to target specific browser vendors and versions to get your page looking right. Neither HTML nor CSS provide an explicit way to do this, but it turns out we can accomplish it with a little knowledge of each browser's particular CSS-parsing problems.

While you can use resources like centricle (described on the right) to navigate the maze of available CSS hacks, I find that I rarely actually need them. Usually I just need to fix something in a specific IE version and there happens to be a way to target them directly that only IE recognizes called conditional comments. Click to open the example, which is described below.

In the example we have two boxes (divs) labeled 'box 1' and 'box 2'. I've used an 'example' class to them both and styled them with this:

div.example { border: 1px solid rgb(0,0,0); width: 300px; margin: 20px; padding: 20px; }

Both divs also have their own id attributes, which I used to resize one for just IE with this code:

<!--[if IE]> <style type='text/css'> div#example_box2 { width: 342px; } </style> <![endif]-->

conditional comment selectors

  • [if IE]
  • [if IE 5]
  • [if IE 5.0]
  • [if IE 5.5]
  • [if gte IE 5]
  • [if IE 6]
  • [if lt IE 6]
  • [if lte IE 5.5]

Try opening this page in both IE and a Mozilla browser. You should notice that in the Mozilla browser they are the same width, but one box is smaller in IE. This is because I didn't use a DOCTYPE on the page, so IE uses Microsoft's box model rather than the one recommended by the W3C. I used a conditional comment to add a rule only IE would see. Because this is modeled like an HTML comment, it can't be embedded directly within your other CSS rules. This is why I had to use the <style> element within the comment.

As you can see from the list on the right you can target specific versions of IE or entire ranges. This is, to me, a better choice than more traditional hacks because here we are relying on a feature of a browser and your code will still validate. Browser behavior with parsing-error based hacks may change over time, which will cause headaches for you if you rely too much on these. Instead, consider using conditional comments.

styling the example site

Now that we know the basics of CSS syntax and where to put the code we write, we now have the basic information to style our blog page. Consider the two boxes below: