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.
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;
}
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:
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;
}
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.
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.
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.
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.
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 |
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 |
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 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).
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.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...
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.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.We certainly hope those examples are helpful. They were fun to do, that's for sure.
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.
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):
Gotta define the structure of the page somewhere... TBW (to be written)
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.
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.
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:
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.
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.
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.
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.