25/11/03
Highlighting current page with CSS
With handy online resources such as List-o-Matic, its now easier than ever to use unordered lists to create navigation. As an extra help to users, why not highlight the current page in the navigation? A recent article on A List Apart called Keeping Navigation current, showed how to do this with PHP. Here’s an easy solution using CSS.
First we’ll set up our navigation list. I have chosen 4 sections for ease, and its best if navigation sections are kept short anyway:
<ul id="navlist">
<li><a href="index.html" >Home</a></li>
<li><a href="products.html">Products</a></li>
<li><a href="faq.html">FAQ</a></li>
<li><a href="contact.html">contact us</a></li>
</ul>
Next we need to add a unique class or id (doesn’t really matter which) to each of the section pages:
<ul id="navlist">
<li><a href="index.html" id="homenav">Home</a></li>
<li><a href="products.html" id="prodnav">Products</a></li>
<li><a href="faq.html" id="faqnav">FAQ</a></li>
<li><a href="contact.html" id="connav">contact us</a></li>
</ul>
Before we leave the HTML, on each of the section pages we need to add a unique id to the body tag:
<body id="home">
This allows us to specify the highlighted tab. After we’ve added the CSS styling for the menu, we add the css rules to highlight the correct tab. As all of these instances use the same rules, we can just list them all, seperated by commas, and the browser will apply the rules to every instance. These overrule the previous styles wherever
is on the same page as .
body#home a#homenav,
body#products a#prodnav,
body#faq a#faqnav,
body#contact a#connav {
color: #fff;
background: #930;
}
I’ve set up some basic pages so that you can see the navigation in action. This allows the navigation to be put into an external include file for ease of updating. The ‘decisions’ as to which button or tab to highlight all happens in the CSS file. This can also be used to introduce different coloured sections. Handy if the layout positioning stays similar and all you want to do is change the colour theme.
48
Tags: 


Previous





Download our vCard
Andy Budd said 1837 days ago:
Like it!David said 1837 days ago:
Nice explanation there -- seen it before, but a well written explanation, to be sure! Yar!Tim said 1837 days ago:
I like it!I usually use PHP to do the same, but this is much easier for small (or non-dynamic) sites.
Joshua said 1836 days ago:
Hey Jon, good article! I've not seen this technique before. I like it more than setting the id="current" in the markup of each page. Seems much cleaner. Thanks! -- Joshuag.wygonik said 1836 days ago:
it may (er, probably) be just an IE6 "issue", but after a few clicks through the sample pages, using the Back and Forward browser buttons cause multiple nav links to be highlighted - one being the current page, and one being the last link clicked. rollover/rollout doesn't change them back to normal. :-\g.
Jon Hicks said 1836 days ago:
I don't get that problem in IE 6 at all. I'm on XP, and it works fine in 5 & 6. Wierd.Jens Grochtdreis said 1836 days ago:
Hi,I came up with the same idea a few weeks ago and decided for myself, that it would bei easier, to style both the list-items and the body.tag with classes. The code you write is a little bit shorter and - of course - it is easier to remember and maintain. the only problem with both variations occurs, if you use dreamweaver and especially dreamweaver-templates. but maybe someday i will find a solution to this problem (to write into the body-tag in a template-driven page).
Greetings from Germany,
jens
Jon Hicks said 1836 days ago:
Greetings Jens!Yeah, you can use either classes or ids - I don't think there is an advantage to either. I prefer ids, simply because it suggest a unique identifier to me.
You should be able to use it with Dreamweaver (probably easier to add the bits into the source view) and with DW Templates, you should be able to specify that the body tag is editable.
Steve Dixon said 1835 days ago:
The IE6 "problem" mentioned above is related to an :active button (at least in my IE6).When you go Back in your browser, the last button pressed is still in focus (as it was when you left the page), so it is :active. If you click somewhere else on the page (ie. move the focus) the button will no longer be focussed, and the :active formatting will disappear.
Just my 2px
Jon Hicks said 1835 days ago:
Wierd, I still don't see it in my IE6 or 5.Tim said 1835 days ago:
Click 'Products', then 'FAQ', then 'contact us' (actually, any order would do) and then click IE's Back-button.Here's a screenshot (IE6/WinXP).
http://www.timspelt.nl/hicksdesign/current.jpg (poor quality, 85 kB)
Steve Dixon (above) is right about it being an :active problem. I'm guessing it's just another IE bug.
Jon Hicks said 1835 days ago:
OK, I've now removed the styles for the active states, so hopefully that'll fix it.Knef said 1833 days ago:
Very useful.audrey said 1830 days ago:
Thanks very much! This is great. Just what I've been looking for.audrey said 1830 days ago:
This is lovely, but something annoying happened. Note, this does not occur with your example, so maybe there's something else in my rather long and unruly stylesheet causing this, but,when I add a comma to the last id in the stylesheet list, this does NOT work in Netscape 7. When I removed the comma, it DOES work in NN7, but does NOT work in IE6.
body#home a#homenav,
body#rsrcs a#resnav,
body#about a#aboutnav,
body#minutes a#minnav,
body#emp a#empnav,
{
color: #fff;
background: #d50100;
}
I ended up repeating the values, like this:
body#rsrcs a#resnav {
color: #fff;
background: #d50100;
}
body#about a#aboutnav {
color: #fff;
background: #d50100;
}
etc....
and it worked fine in both. if you have any insight, it would be greatly appreciated.
Jon Hicks said 1830 days ago:
The last selector in the list shouldn't have a comma, but it should work in IE6. Could you post the full code somewhere?jojo said 1824 days ago:
Looks nice at default text size but it is falls completely apart if you increase the text size... Why do you assume that everybdoy will look at it using the same text size?Jon Hicks said 1824 days ago:
Calm down JoJo, I don't assume that at all. You're missing the point. The purpose of this is to show how to highlight the current page or section, using HTML markup that can be the same for all pages (so that the nav can be used in an include file).Ignore the design - I took it from List-o-matic (http://www.accessify.com/tools-and-wizards/list-o-matic/list-o-matic.asp) to save my time.
Nic said 1822 days ago:
currently redesigning above (HATE the way it is using tables, blah!)Anyway, just wanted to let you know that this is a great technique and I'll definately be using it as I prefer to do my navigation using CSS rather than JS rollovers-too many images, to much code.
It was really easy to follow too which makes it great when your going through a dozen pages at a time trying to find something. :)
Nic
g.wygonik said 1786 days ago:
well, the removal of the active states did fix the problem (at least for me). great technique! :-)g.
Clive Sweeney said 1779 days ago:
The CSS works fine on the appearance of the current page link, but this still leaves the issue of having an active link to the current page, which is not a good idea.I wonder if there's any solution to this that doesn't involve either scripting or changing each page individually.
Jon Hicks said 1779 days ago:
Clive, I'm not sure what you mean. Can you expand?Tom Sherman said 1776 days ago:
Hi Jon. Lovely site. Just stumbled upon it.Allow me to add a simple suggestion. I recommend using a CLASS for the BODY and an ID of the same name for the navigational link. This makes it very easy to keep track of.
Example:
(CSS)
BODY.home A#home { color: green; }
-----
(HTML)
[body class="home"]
[a href="/" id="home"]home[/a]
-----
One more thing. For those who use SSI to manage their site, I recommend setting the value of a VAR (call it "pageID"). This should be done before you call your included file with the BODY tag. Then use an ECHO (in the include) to insert the VAR in the BODY tag.
I know I'm not explaining this very well, but if it sparks anyone interest, feel free to email me. (My addy is at my website.)
Jon Hicks said 1776 days ago:
Tom, thanks for your kind words!Sure, whatever works for you,.
As for the setting of a VAR - thats what I do currently, but that seemed like a seperate issue to the navigation highlighting, so I didn't cover it.
Tom Sherman said 1775 days ago:
Jon, the SSI stuff definitely is separate, but I just found myself staring at your article saying, "Yes, that will work, but how am I going to automate it?" Of course the answer is different depending on one's content management setup, but I think for everyone's it would involve:1) Manually setting the BODY id/class in your "main pages" (those linked in your navigation), perhaps by setting the value of a variable
2) (if necessary) Echoing the value of this variable in your template, if your template contains the BODY tag
One a totally unrelated note, your JavaScript comment previewing is totally sweet. Can I swipe your code if I appropriately credit you? :)
Jon Hicks said 1775 days ago:
Thats right - not everyone will have the body tag in the include file. I'm planning on doing a seperate article on php includes anyway.Comment previews: http://www.hicksdesign.co.uk/journal/archives/000317.php
John Jones said 1765 days ago:
How can I implement the highlight page when I have my tag in my header include and my tag in my footer include.It is not good practice for me to include the body tags again in my content DIV. I have tried placing a anchor with id="mainpage" at the top of one of my pages but the CSS seems to ignore this and does not highlight the option on my unsigned list.
Jon Hicks said 1765 days ago:
John - first of all it doesn't affect your footer includes. Secondly, how do you include your files? A HTML virtual include or something like PHP? IF you use php, all you have to do is set the id tag as variable.I have an article on this coming very soon!
John Jones said 1764 days ago:
I use PHP includes. I have the start of the BODY in the header and the end of the BODY in the footer. The rest of the pages appears in the middle in my CONTENT Div. What I need to do is assign a variable to the top of each page so that the CSS can highlight the menu. Just not sure how to go about this as I am fairly new to CSS.Jon Hicks said 1764 days ago:
No problem - you do it all the php. When you do your include, set a variable:<?php
$bodyid="contact";
include("head.php");
?>
In your include file you do this:
<body id="<?php echo$bodyid; ?>">
John Jones said 1763 days ago:
Thanks for the response. I will try as you suggest and let you know how I get on.John Jones said 1763 days ago:
Ok, not quite sure exactly what you did but it works a treat. Thanks.Jon Hicks said 1762 days ago:
What you're doing is telling php to insert the word 'contact' wherever you tell it to. So you can keep the one include file, but change its contents depending on what information you feed it.John Jones said 1762 days ago:
Ok, I understand now. Another question though.This is fine if all my pages are seperate, but what if my navigation menu all points to the same page but the content is loaded dynamically from a database. How would the CSS know which menu to highlight?
kjf said 1762 days ago:
This is great! and very timely as I was just trying to think up a css solution today. I wonder what I would have come up with? I guess I will never know...Thanks a mil, youv'e saved me some time :)
Jon Hicks said 1762 days ago:
John - do you mean when adding the variable on the url like this..... home.php?bodyid="contact" ?John Jones said 1760 days ago:
Jon,Re: above.
If my navigation menus all point to the same page but the page content is based on a database search, then I am always displaying the same page. Would I need to put an entry in the database so that it knows which button to highlight? (e.g. bodyid=category_name from database)
Jon Hicks said 1760 days ago:
John , I'm still not 100% clear on what your set up is, but all you need is some way of declaring a value for the variable. So if you already have your page content in the database, it should be easy enough to add the value for the body id.John Jones said 1759 days ago:
That was exactly what I thought, have the variable declared from a returned record and assign it in the CSS accordingly.Thanks a lot, you have been a great help.
John.
Sam Rae said 1758 days ago:
Thanks for that—my php navigation was getting a bit messy. Fantastic site, btw. I think it's honestly one of the best looking sites I've seen it a while. Great to look at and easy to read.Jilles van Gurp said 1745 days ago:
Nice solution but it still seems somewhat like a hack to me. What I don't like about the solution is the need to mention each pageid in the css. Really the point of having css is to separate content from presentation.Wouldn't it be possible to just test with a javascript what the id of the body is and then simply look for the corresponding li id (shouldn't ids be unique anyway??) and enclose it with a div class="selected"? That would still be a hack (because of the ids) but at least you get rid of referring to specific content in the css.
Jon Hicks said 1745 days ago:
Eh? Sorry, I really don't see your problem here.You have an id in the body tag, and id for the nav item, and then some simple css rules in the stylesheet. Thats all.
The ids could be argued as not being presentational too - they describe the page, rather than adding solely presentational markup.
I really can't see how resorting to javascript is necessary, and whats the problem with referring to the ids in the css anyway?
ben morrison said 1731 days ago:
Firstly I like your solution.What I've started to do is check the pageid then write in the < a > tag or leave it off if the id is the current page. One of nielsens top 10 mistakes was 'pages that link to themselves' - I dont follow everything nielsen says. So your < li > will have a different style to your < a >
ben
ben morrison said 1731 days ago:
preview showed spaced out tags, post didnt. so basically add "a" tags or not. style 'li" and "a" tags differently.kirkaracha said 1724 days ago:
You could indicate the active section without it being a link by doing this:[li id="homenav"][strong]About[/strong][/li]
And putting this in the style sheet:
body#home li#homenav a, body#home li#homenav strong
Joey said 1724 days ago:
Jon, I think what Clive Sweeney was trying to say above is that you shouldn't have links that point to the same page you're sitting on (i.e. when you're sitting on the products page, there shouldn't be a hyperlink that points to the products page). There's something in the W3C specs that says that, but I'm not sure where.Many sites use server-side scripting (or they code by hand) to remove links that point to the current page, but they will leave some sort of styled text in place of the link to show what page you're on (and so the nav area stays consistent).
I'm trying to find an example, but I'm having trouble. Maybe I'll comment again when I can find one...
Jon Hicks said 1724 days ago:
Joey, yeah I realised after Bens comment what Clive was on about.It makes really good sense to remove the active link to the current page, but you will have to use some sort of script to do it (or code by hand). The solution I've given here allows you to use the nav in an include file without any scripting. If you were going to remove the active link, you'd be better off using something like the php solution at A List Apart:
http://www.alistapart.com/articles/keepingcurrent/
..and adding some 'if...' statements to decide whether it should output a link tag or not.
misterx said 1721 days ago:
Very elegant. Well done. :)I suppose you could get really fancy and actually change the html of the current page using display:none. I think I'll do that.