Submitted by kplawver on Wed, 2006-04-26 13:41.Themes

Introduction

This document is meant for people who know the basics of CSS, but may not be as familiar as they could be with positioning and the idea of specificity. We're not trying to cover everything there is to know about CSS, because it's one page on one Web site. It takes volumes and volumes of single-spaced small type to cover everything. If you're not familiar with CSS, there are many good resources (whole Web sites, in fact) on the Internet where you can learn all about it, and some really good books as well. We've listed some of our favorites in our Resources For Learning CSS section.

This document is the "parent" of documents aimed at module developers and very shortly one aimed at page style template developers. We're going to do a short overview of terminology and CSS to make sure we're all speaking the same language, then go over specificity and positioning in more detail (because it's the most important part of this whole thing – other than you, of course), our "skeleton" style sheet and the things it sets as logical defaults, and finally wrap up with some best practices that apply to everyone.

One area in which modules and pages will need to work together and "play nice" is in what CSS is applied to pages and how that CSS might have unintended effects on the rest of the page. As module developers, we need to make sure that our modules don't stomp all over the page's CSS, and vice versa.

Terminology and Basic Overview

CSS was invented by Bert Bos and Håkon Wium Lie in the early 1990s. CSS1 became a W3C Technical Recommendation in 1996. CSS2 became a Candidate Recommendation in February of 2004. Unfortunately, adoption of CSS by both authors and browser makers has been slower than many of us had hoped, and the browser used by most Internet users doesn't support a number of the CSS2.1 properties that would make this whole CSS thing a lot easier. But, we make do with what we have, right?

A simple CSS declaration looks like this:

h1 {
	color: red;
}
  • The whole thing is called a "declaration."
  • The text in red is the "selector."
  • The blue text is a "property."
  • The green text is the "value" of the property.

We'll talk in more detail about specificity in the next section, but before we do that, we're going to talk about the different kinds of selectors we can join together:

Type

The type selector is the one we used above. It selects all elements of that type and does something to them. Here's another example:

p {
	margin:1em 2.5em;
	padding:.5em;
	color:#000;
}
Descendant

A descendant selector is like a type selector, only it searches for all descendants of the first element before styling them. Here's an example:

p strong {
	color:#900;
}

This selector tells the browser to take all strong elements that are descendants of all p elements and make them red.

Class

Now we're getting tricky. Class selectors style any element with the specified class. For example:

.error {
	border:solid 1px #c00;
}

Now, any element with a class of error will have a bright red border. You can limit what the selector selects (this is why it's called a "selector") by pairing the class selector with a type selector, like this:

p.error {
	color:#c00;
}

Now, only paragraphs with a class of error will have the red border.

ID

If you want to select an element that has an id, you'd use an id selector (really). Here's what that looks like:

#nav {
	float:left;
	margin:0;
	padding:2em;
	border-right:solid 1px #000;
}

That takes the element with the id nav and: float it to the left, makes sure it had no margin, gives it 2em's of padding on all sides, and gives it a 1 pixel wide, solid, black border on the right side.

The reason for this will all become clear in a minute when we talk about specificity.

Specificity

The selectors we talked about above allow us to slice and dice our document into easily styled chunks. As long as the document is logical and uses good markup, we should have a fairly easy time writing the CSS for it. Where we run into trouble is when we get unexpected markup, or have no control over the markup, and may accidentally style things that we shouldn't, or have styles that apply to more elements than we should. This is where knowing about specificity helps.

Specificity is an order of operation for CSS. It sets up a logical hierarchy for which declarations are more specific, meaning they'll override less-specific selectors. Here's an example that has two selectors in it. See if you can figure out which one is more specific before I tell you:

h1 {
	margin:0;
	padding:.2em;
	color:#009;
}

#body h1 {
	margin:.2em 0;
	color:#333;
}

Did you figure it out? If you said the second one, go get yourself a gold star, piece of candy, a soda, or a milkshake – because you're right! Why are you right?

It's not because the second selector has two pieces to it. It's because it has an id selector as part of it.

Specificity is fairly simple when it comes down to it. (there's also the Star Wars way if you want to read that one). There are four columns of specificity (but we're going to worry about only three of them, because none of us is going to use !important, are we?

style attributes, !important and user style sheet id class type

Since module developers shouldn't use the style attribute, !important creates a whole host of problems that we won't go into here, and we can't do anything about user style sheets, so we'll ignore that column. But, here's how the order goes. The column to the left always trumps the column to the right of it. So, even if you have a 10 in the type column, if there's a single class in your selector, that selector is more specific and it can override the styles in the first. This is easier to see in examples. Here are a bunch of examples of different kinds of selectors with their specificity table below it. Since we're not going to be using style attributes or !important, we're going to leave it off of the tables below (because it makes them ugly).

Here's the markup we'll be using for our example:

<div id="nav">
	<ul class="primary">
		<li id="homeTab"><a href="/home">home</a></li>
		<li id="aboutTab"><a href="/about">about</a></li>
		<li id="helpTab"><a href="/help">help</a></li>
	</ul>
</div>
<p class="error">You've done something horribly wrong. Please don't do it again.</p>

And here's the CSS with its specificity table and a short description of what the declaration is going to do.

Example One

You should recognize this one. It puts a 1-pixel, solid, red border around any paragraph with the class of error.

p.error {
	border:solid 1px #900;
}
id class type
0 1 1

Example Two

This is a lovely selector. It takes any descendant list item of any unordered list with a class of primary inside of an element with the id nav, gives it a solid, 1-pixel, black border on the bottom of the list item, and sets its font size to .9em.

#nav ul.primary li {
	border-bottom:solid 1px #000;
	font-size:.9em;
}
id class type
1 1 2

Example Three

This selector is super-specific, and that's super. It's looking for a list item with the id homeTab that's a descendant of the element with the id nav. It makes that list item's text bold. Hooray for specificity!

#nav li#homeTab {
	font-weight:bold;
}
id class type
2 0 1

Starting to become clearer? Let's see if we can recap the rules before we move on to positioning:

  • The column to the left, if greater than zero, beats all columns to the right. That means:
    • If there is a class, it doesn't matter how many type selectors you've stacked up.
    • If there is an id, it doesn't matter how many class or type selectors you've used.
    • two ids are always more powerful than three classes.
  • If selectors have equal specificity, the one specified last "wins."

Positioning

The other problematic topic we need to make sure we're all clear on is positioning. There are a lot of options for moving elements around on a page with CSS, but not all of them play nice when we're talking about building small pieces that need to fit into larger pages with their own styles. Things can get funky very quickly. So, here's a quick review of the kinds of positioning that today's browsers support (and one that everyone but Internet Explorer currently supports).

static
This is the default. The element exists in the normal flow of the document.
relative
The space for the element's box remains, but the element can be positioned relative to its starting position. This means that "0" when using top and left properties on these elements is the top left corner of the box's original position in the flow. Think of it like a piece of paper. Using relative is like cutting that section out of a piece of paper. The hole where the box was still exists and nothing is going to fill it, but you can now move the cut out piece around.
absolute
The element is now totally out of the flow and other elements ignore it. It is positioned relative to its containing block.
fixed
The element is out of the normal flow, but its position is "pinned" to some reference and, in most media types, doesn't scroll. For fixed positioning, top and left are relative to the "viewport" (the browser window). This is the one that's not supported by Internet Explorer for Windows.

Notice that I didn't mention float or clear once. They were never meant for positioning large pieces of a document, but for positioning small chunks of text such as sidebars in a book. Unfortunately, because CSS doesn't currently have anything better to offer (well, it does, but we can't use it until Internet Explorer supports it–our left foot for display: table), we're stuck with using float. This means we have a lot of compensating to do, which means we can run into problems.

You want a review of float? OK, if you insist. Floating an element takes it out of the flow and pins it to the left or right of the containing element. The weird thing about floats is that the text in elements that come after the floated element flows around the floated element, but blocks ignore it as if it were positioned absolutely. This can cause a lot of confusion, until you go back and remember why float was introduced in the first place.

To get an element to force a break below a floated element (or all floated elements within that containing block), we use clear. You can clear to the left, to the right, or both, depending on your desired result. Unfortunately, the cleared element will clear below all floated elements in that "flow," which, when we're dealing with modules inside of larger pages, could have unintended consequences.

To avoid the problems associated with float, especially when building the CSS for modules, we rely on position: relative to help us keep floated elements under control. Because positioning elements relatively creates a new flow inside that element, floats shouldn't affect any other floated elements that may be to the left or right of them. More importantly, using clear inside a relatively positioned element won't clear elements outside of the relatively positioned container.

When we get to the skeleton, you'll notice that all columns and modules use relative positioning. We'll address module-specific concerns about floating and positioning in the best practices document. Let's see, have we covered positioning? You want some examples? Sure!  All of these examples use the HTML provided by the CSS Zen Garden, because it saves us having to write it , and it's already shown it's really good for showing the power of CSS. It's probably a good idea to have the source open in a text editor, and the example open in another browser tab or window while reading this. Follow the bouncing ball...

  • static: There's no CSS at all, which is a great example of static positioning, since it's the default. See how all the block elements are shown one right after the other? That's static for you.
  • relative: This is where we start using some of the logical defaults from the skeleton, plus center the page so moving bits around looks OK. We're going to play with the header a little bit. We're going to be working inside the pageHeader div. We're going to make the h1 overlap with the h2 that comes right after it by a half an em or so, and scoot it to the left the same amount. You can check out our very simple stylesheet if you want.
  • absolute: Don't try this at home, or at least, don't try this with modules, please. Still playing with pageHeader, we're going to positition it absolutely (totally) to the top left of the viewport (the browser window in CSS terms, in case you were curious). Remember, if you position something with absolute, you have to make sure you clear a spot for it or all the content will come right underneath it, which isn't what we want, is it? Here's our CSS file.
  • fixed: For you Internet Explorer users, this is going to look exactly like the absolute example. For everyone else, it'll look just like it too until you scroll. What?! Holy cow,  no scollage, Batman! CSS is awesome. Le CSS est ici.
  • float: We're bored with simple examples, so we've gone a little crazy with this one and, well, all sorts of things are floated. We've made three columns, all floated left. If we'd want to change the  order in which things are  displayed, we could have floated one or two right and another left, or not floated the last one at all. You should try it yourself just to see what happens. You can even have our stylesheet to start.

We certainly hope those examples are helpful. They were fun to do, that's for sure.

The Skeleton

The style sheet we're calling the "skeleton" contains just enough information to make pages usable and set module and page style developers up for "success". It will set logical defaults, define some page sections, define how columns work, and set some assumptions about module appearance. The skeleton is written with as little specificity as possible, so it should be easy to override by module and page styles.

You can see our skeleton if you check out our example page, or you can go right to the CSS Skeleton.

Logical Defaults

There are "default" (called user-agent) styles in every browser, some that probably no longer make sense. There are also frequent,  alarming issues we can remove by resetting those user-agent styles to something that meets our needs. This is risky stuff, but we hope we've done a decent job of picking the most problematic elements to "fix." We've kept things extremely generic so they're all easy to override. Also, since the skeleton will come before any module or page styles, you can even use the same selector and be fairly confident that your style will be the one that appears (because the page style sheet will be loaded after the skeleton so even if you use the same selector or one with the same specificity, you'll come later in the cascade, so you win!). We're not using any crazy properties that you weren't already going to set anyway, and left defaults where possible (hence the use of margin-top instead of just resetting all sides with margin). Here are the highlights (selector followed by explanation we'll spare you the actual code):

body
We set the margin and padding to zero, and set default background and foreground colors. We also specified a default font and font size.
h1, h2, h3, h4, h5, h6, ul, ol, form, p, blockquote
We removed the margin, and given them all reasonable (.5 em) top and bottom padding. This is all to get past margin collapsing, which can cause all sorts of goofy looking stuff, especially with headings.
a
We removed the underline and set a default color (yes, they're still blue).
a:hover, a:active
The underline shows up on hover, and we picked a slightly lighter default color.
a:visited
Visited links are a darker blue than the default link color... because purple reminds of us some other Internet company.

Page Sections

Gotta define the structure of the page somewhere... TBW (to be written)

#header
#nav
#content
#footer

Columns

Modules go into columns, which are all inside of the div with the id content. They're kind of crazy at the moment, but will hopefully become less so.

.column
All columns are floated to the left, positioned relatively, and have 5 pixels of margin to the right (4 pixels in Internet Explorer for Windows... stupid double margin float bug).

Modules

.module
All modules are positioned relatively. All modules also have a 1-pixel solid black border and 1 em of top and bottom margin.
.head
.body

Re-usable Pieces

This used to have a link to our internal wiki, which is very rude of us. We're sorry about that. I've removed it, and we'll actually fill in this section in the very near future. Remember, it's an alpha.

What Does It All Mean?

You may be asking yourself what all this has to do with you. It has everything to do with you, if you're going to create modules or page style templates. In order for things to work properly, you need to be able to create four levels of styles for pages that use modules:

  1. skeleton styles
  2. module styles
  3. page styles
  4. user-specified styles

All four levels require some expectation of what's come in the level(s) before, and how specific they need to be in order to get the desired effect of each stage. That means we need to set some specificity guidelines in order for modules to be able to style themselves without breaking either the page or user-specified styles, style the page without breaking the user's styles, and so forth. To do this, we've set up a table on the best practices page that shows what we recommend you set for specificity for each type of style sheet you'll be creating.

Conclusion

Hopefully, this document has cleared up any confusion you may have about CSS specificity and positioning and explains why we've set things up the way we have. We do have more information, if you need it. If you're building modules and need more information, we have the Module Best Practices page. If you're going to be building page style templates, we have Creating Style Templates For Pages.

If this isn't clear at all, please head on over to the message board and we'll do our best to clear it up for you.

Resources For Learning CSS

No one is perfect,. There are no more than a dozen people on the planet who know everything about CSS , and this author is not one of them. So, don't feel badly if you don't know it all or need to look things up. If you don't know CSS yet, here are some resources that have helped us and we think can help you join the cool kids in the CSS pool. Because CSS doesn't work without having some markup to style, it's probably also a good idea to learn about semantic markup and get familiar with XHTML.

Free Online Resources

Books

As far as we know, no one has made a documentary, feature film, video game or music video about CSS yet. But, if one comes up, we'll post a link to it. The best we can do is a couple of jokes written in CSS.