Let’s say you want to change the color of your links on just your contact page to red. They are blue on every other page, but it just makes sense for them to be red on your contact page (for some reason). There are a couple ways you could go about this.
- You could declare a separate stylesheet for your contact page. This isn’t ideal, because it’s redundant. If you make any other changes, you’ll always have to make them both on the main stylesheet and the contact page stylesheet.
- You could give all those links a unique class on that page. This isn’t ideal, because it isn’t very semantic and it’s also redundant. Why apply a class to every single link on the page when they really aren’t any different from links elsewhere on the site, contextually speaking?
- The best solution is to give your the body a unique ID. This solves the problem perfectly. You can use the same stylesheet and target just the links you want to with a single CSS selector.
How it’s done
Simple, literally just apply the ID to the body tag:
...
</head>
<body id="contact-page">
...
Now for our example of making all links on the contact page red instead of blue, just use some CSS like this:
a {
color: blue;
}
#contact-page a {
color: red;
}
How about a more practical example?
You got it. One of the most useful implementations of this technique is within navigation. Take a look at this sample navigation:
See how the forums tab is the “active” tab? Certainly that’s just a slight change in CSS, probably just a shift in the position of a background image. Perhaps the XHTML looks something like this:
...
<li><a href="/fieldtips">Field tips</a></li>
<li class="active"><a href="/forums">Forums</a></li>
...
The “active” class applied to the list item is what shifts the background image. That’ll do the trick, but what about when we move to the Field Tips page? We will have to remove the active class from the forums tab and apply it to the the Field Tips tab. That’s not very convenient. That means the code for the navigation block is unique on every single page of the site. So let’s say down the road we want to add a Contact tab, we’ll have to alter the code on every single page. No fun.
Let’s do this a little smarter. First we don’t want to include the navigation block of code on every page, we want to include it, probably with a simple PHP include like this:
<?php include_once("nav.html"); ?>
But then how do we apply the “active” class to the current navigation list element?
This is where apply what we just learned about giving unique ID’s to the body! Instead of applying a class to only the active list element, let’s apply a unique class to each separate list item as well as give our body an unique ID.
...
</head>
<body id="field-tips">
...
<li class="fieldtips"><a href="/fieldtips">Field tips</a></li>
<li class="forums"><a href="/forums">Forums</a></li>
...
Now we can target specific elements in the navigation with some clever CSS:
#field-tips li.fieldtips, #forums li.forums {
background-position: bottom;
}
This means that the code for the navigation block can stay the same on every page, yet only the navigation element native to that page will be affected by this CSS and “flip” to the active state.
Let’s get even more dynamic
Reader Brian left an awesome comment on how you can use PHP to apply the unique ID to to the body element:
<body id="<?= basename($_SERVER['PHP_SELF'], ".php")?>">
This will return the name of the PHP file being executed as the ID (e.g. body id=”index.php”). To leave off the .php part, just remove the “.php” part.
Wow, this is very useful, thanks Chris.
Great article and topic. Ironically enough I was actually thinking about writing on this exact same topic this morning. I got distracted on another topic so I didn’t, but kind of funny.
There is only one word to describe this: bad-ass-ery
Thanks fellas!
This is a good tip for websites that use different colours etc for different sections of websites. One good example is ICWA which I help maintain.
Sounds good in theory, and I have used this technique many times on static sites, but on big database driven sites, as a UI guy I find that the back-end dev types hate it because it means they can’t use the same code for the body elements throughout the site (eg. with .NET master pages). Having said that, it’s only a little more work for them to get this working nicely (alebeit with a bunch of moaning and groaning :-P).
…which of course you kinda addressed with the PHP snippet.
you missed one rather obvious fourth option: call your general stylesheet as usual, and then either call another stylesheet (if it’s a set of pages you want to style slightly differently) or add a style block in your document’s head (if it’s a single page), redefining just the rule/s that is/are different. as long as you do this redefinition after your call to the main stylesheet, you can use the same specificity as in your main stylesheet. this takes advantage of the cascade, doesn’t burden you with having to duplicate the entire main stylesheet just to change one or two things, and doesn’t mean that you have to start a whole body ID thing.
@hank: Yep, on sites that use any kind of dynamic framework at all it is very common have a index or header file that is common to all pages on the site. That means it’s a little more difficult to get that unique ID in there, but as we both know, it can be done =)
@patrick h. lauke: Yes that’s true, you could include an additional stylesheet or style block AFTER the original stylesheet that will over-ride rules set up in the original stylesheet. There is something that bugs me about this, and maybe it’s just a personal thing that I need to get over, but I just don’t like it. To me it’s not really “taking advantage of the cascade”, it’s declaring two identical selectors, letting them clash, and letting the browser decide which one it’s going to honor. Maybe there are some specifications on this (there probably are), but I just like the idea of being more specific in my CSS rather than declaring identical selectors.
chris, fair enough – and admittedly it would get cumbersome to do, say, the navigation example with my method (but for quick one-off redefinitions i’d still say it’s less work than trying to keep all special cases in the general stylesheet and applying them with more specific selectors for the page in question).
for reference, the case of redeclaring aspects of one style with a subsequent one is covered clearly in the spec as part of the cascade rules, so it’s not a case of error handling / clashing left up to the browser.
“4. sort by order specified: if two declarations have the same weight, origin and specificity, the latter specified wins.”
CSS 2.1 / 6 Assigning property values, Cascading, and Inheritance / 6.4.1 Cascading order
Generally, if you have a common header for a site you would declare the page ID at the top of the page and call the header include below it.
At least that’s how I do it in Cold Fusion.
Great tip.
Using the same way, we also can do some internationalization of css (ex.: background images with text on), for the example we will use a class to the body:
So, in the body tag, you can for internationalization of css add a class, just like:
<body id="some_page" class="french">
<h2 class="hello_world">Bonjour le monde !</h2>
or
<body id="some_page" class="english">
<h2 class="hello_world">Hello world !</h2>
Then in the CSS, we can do things like:
h2 {
text-indent: -5000px;
height: 30px;
width: 300px;
background-repeat: no-repeat;
}
.french h2.hello_world { background-image: url(french_hello_world.gif); }
.english h2.hello_world { background-image: url(english_hello_world.gif); }
etc...
After that, it’s the developers choice how to dynamically change the class, I personally with PHP do something like:
<body id="some_page" class="<?php echo $language; ?>">
<h2 class="hello_world"><?php echo $title_hello_world; ?></h2>
This is a really old trick – I’ve been using it for ages.
To take the nav example further, if you add a class and an id to each body tag, you can use the class to open the current section of the nav, and the id to highlight the current page – e.g. in a drop-down or explandable nav.
You can also then use the body class to change the look of each section of the site. With multiple body classes, you can change the look based on site section and page type (index page, article, contact form, etc.)
As a general rule, don’t re-use a page id: use a class if you want to share styles across multiple pages, and use an id if styles are unique to one page.
Funny how someone mentioned he “thought” about writing a similar article, while I actually did :)
I agree for the most part (though I wouldn’t use the body id to style an active navigation item). The only remark I have is to work with ids and classes, where the id would define an area within a site and the classes would further specify this area (fe you could have 2 contact pages, 1 in each area of your site).
I wrote about it here
Well, I always put an ID named “current” in the <li> tag that shows the link for the actual page, like this:
<li id="current"><a href="?op=link1">Link 1</a></li>
<li><a href="?op=link2">Link 2</a></li>
<li><a href="?op=link3">Link 3</a></li>
...
For do this, I have a PHP loop that iterates through all the LI tags and verify if the target of the link is the same as the requested page — passed by the $op variable.
This works fine for me, since all my links defines a variable called $op, used to include the requested pages in the main content of the principal page.
[excuses for the bad english; just another brazillian guy trying to learn some cool stuffs :)]
This is a great trick and I’ve used it in my framework for a few years now.
In addition to the ID representing the current page(-type) I also have a few classes that I find quite useful:
<body id="home-page" class="rainy morning js-disabled not-logged-in">
The first thing I do in my JS is $(‘body’).addClass(‘js-enabled’).removeClass(‘js-disabled’); The weather-classes are generated from http://developer.yahoo.com/weather/
Also, to avoid using a class or id in every navigation-item I’ve started using attribute-selectors instead:
#home-page #navigation a[href=”/”], #about-page #navigation a[href=”/about/”] { /* selected nav styling */ }
Granted, relying on the href-attribuets may be a bit unsafe but I’m the only developer on my site so it’s alright for me.
I also append ‘-page’ to the body-id to avoid duplicate IDs.
Good post!
ya, with this way you can get more better control,
thanks Chris Coyier for this tut
Great work! Never played around with the body tag before, can’t wait to implement it on my next project.
Hello, I recently learned this trick from another site, but have a question maybe you can answer…. I have a main navigation that I have effected by the body id trick. But on my interior pages I have another sub-nav that I would like to also have the same effect, when one of the items is clicked, I’d like for it to continue to be highlighted when the new page loads.
Any ideas?
@phillip: You could add classes to the body tag of your subpages. Like:
Then use the ID to control the highlighting of the main nav and the class to control the highlighting of the sub nav.
Good post but I have a question: how can you change the css using the Id from the body tag to change the stileshet like http://www.csszengarden.com is doing.
How does the id=”current” trick work? Does it work without body id (or other id), without php or javascript?
How can the browser know, which is the current page?
We’ll years after this was written I found it very useful and made my life so much easier. Thank you. I used this in my PHP headers and it worked awesome with my sprites from the static version. Any way if you see this comment can you let me know if things have been updated since? Thanks again.
Nice trick! But what do you do in the case of a dynamically generated list? Have PHP generate CSS? Seeing as I almost always need to generate menus based on database content, this is not a good option… And I most certainly do not want to have CSS in my HTML. What if I compile with LESS or Sass? Or am I missing something here?