I’ve put up an example page to demonstrate the technique I’m using for pure CSS tabs. As you can see from the source, the tabs
are actually an unordered list of links. Rotating the list into a set of horizontal tabs is accomplished entirely in CSS.
The obvious
method, in the sense that any advanced CSS can be considered obvious, would be to set the <li> elements to display: inline. This is, in fact, what display:inline is for. Unfortunately, this approach fails in a variety of odd ways in a variety of browsers. Internet Explorer for Windows adds padding to the right of each item which is not covered by the link (thus destroying the tab
effect when highlighting the link). Internet Explorer 5 for Macintosh just goes all wacky.
The technique demonstrated here (and that I’m currently using throughout my site) accomplishes the same effect, but it sets each <li> element to display: block and float: left, and then uses a dummy element after the list to clear the float.
(Boy, I really sound like I know what I’m talking about, don’t I? In reality I have only the vaguest understanding of floats. This technique quite literally came to me in a dream, and I hacked the details until it looked good in 4 major browsers. This CSS stuff is hard; don’t let anybody tell you different.)
Then there’s a bit of wacky positioning: I use position: relative; top: -1.32em to line up the tabs to the bottom of the logo area. Not 1.33, which would make the tabs too high in Camino, and not 1.31, which would make the tabs too low in Mozilla. All of this is no doubt dependent on the font-size of the tabs. Doing everything in pixels would be easier but wouldn’t scale properly in Internet Explorer for Windows (thanks, Microsoft).
And since we’re using floats, we need a dummy element after the list to clear the float (display: block; clear: both). Except that we don’t need to do this in Internet Explorer for Windows, for reasons that are not at all clear (no pun intended). In fact, the presence of a clearing element in IE/Win makes everything go completely out of whack. So we use a CSS hack to make the spacer invisible (display: none) for IE/Win but visible and clearing for everybody else.
After all that, it works in Mozilla 1.3, IE 6 for Windows, IE 5 for Mac, Camino 0.7, and Safari build 60, but not Opera. In all versions of Opera, the tabs do not line up to the bottom of the logo area; they’re not even close. Phooey. It’s live anyway. Suggestions welcome.
Update: through judicious use of my *7 CSS hack (a hack so unpopular that even the fine folks at the css-discuss wiki have attempted to discredit it), I have gotten this to work in Opera. Thanks to absolutely no one who suggested this, and double thanks to the Opera employee who suggested that I change my tabs so that they worked in Opera and nothing else.
Further reading:
§
Phooey? But it _does_ work in Opera 7 PC
Observe: http://allyn.karynova.com/images/diveintomark1.gif
:)
Anyway, I like it, nice work.
I have O7 PC as well, and I think that the tabs are supposed to more smothly allign with the bottom of the colored area, as they were before the “All CSS” method was adopted. Of course, I read this all in a newsreader anyway, so I don’t really care ;)
Cool. I suppose there is no real “correct” way of doing this stuff so long as it works eh?
Keep on.
— Marty ![]()
Yeah, I assume that Mark was referring to the gap between the tabs and the bottom of the header area when he said it didn’t work in Opera 7. Hey, At least it’s usable and clean, if not quite perfect.
Hmm, although strangely, when viewing the site in Opera 7 for Windows, the tab links sometimes stop working. I was flipping through the tabs looking at the different colors, and then the tabs stopped responding as links. No hover colors, no hyperlink pointer, no hyperlinking when clicked. Very odd, but I’m not sure what triggers it, or maybe it was just that I was clicking on the tabs too fast.
Reminds me of http://www.sovavsiti.cz/css/horizontal_menu.html
— matthew ![]()
Just yesterday I thought up a way to make this site look like it did the first time you had this design (and, I think, a little better). (This is in fact probably IE only, but that’s only because I couldn’t get the technique I mention below to work in Mozilla for some reason.)
I use the Proxomitron ( http://www.proxomitron.com ) and a set of rules inserting the id diveintomark-org-html on the html tag (so that my multisite stylesheet could control individual pages via classes (body#diveintomark-org.index doesn’t seem to be valid)) and inserting http://wootest.net/css.php as a stylesheet. I tried having the hover tabs have the background image on hover but in fact it didn’t look too well. Feel free to try this out, I can give you the exact rules on request.
— Jesper ![]()
Mark,
I’m writing this from a cybercafe in Belgium – looked up your site and got a couple of messages about how their computer has dialers and spyware installed.
How the hell did you do that?!
I was thinking, why isn’t it working for me? But you never meant it to let it work just like the glazman css-only tabs, found here:
http://daniel.glazman.free.fr/weblog/targetExample.html
(only working in the Mozilla 1.3)
Never seen that one?
There’s also this example of css tabbed navigation, which you may have seen:
http://nontroppo.org/test/tab1.html
— Tim ![]()
I have used the same style of doing menu bars as well both on my site and for a few work pages I have done.
The one thing I can’t seem to get is fixed tab sizes. I can’t seem to get the width of all my LI tags the same.
Anyone manage that?
Actually just figured it out. You need to set your li tags to display block as well, then you can set the width of all your tabs to be the same.
Oops I mean set you anchor tags in the li to be block.
Misaligned in Opera 6.1 on linux..
— kasia ![]()
using images:
http://alex.netwindows.org/tabs/tabs-example2.html
derived from a cleanup I did for a clients totally fsck’d Dreamweaver JavaScript tab setup:
oops, forgot to mention that the above won’t work on lame browsers (IE, for example)
See my vewsion on CSS manu, based only on <a> styles.
[link removed]
@lex, I removed your link because:
1. You seem to be plugging your company. If you really wanted to just show us a CSS example, you would have put up an isolated test page.
2. The technique you’re using does not use proper list markup, which is a prerequisite for this discussion.
— Mark ![]()
A List Apart has a good article on this as well:
http://www.alistapart.com/stories/taminglists/
— Adam ![]()
Great code, which I’m attempting to re-use (in part), however, when I try to validate your CSS with the W3C validator, I get “Parse Error” for the part for changing the colors of the active tabs…
http://jigsaw.w3.org/css-validator/validator?uri=http://diveintomark.org/
Off-topic, but in answer to Thomas, the spyware notices are generated by a script that searches for installed Class-IDs of known parasites. More info here:
You can install the script on your own server (as I have):
http://doxdesk.com/software/js/parasite.html
— Mark ![]()
Good call on the CSS validator! Fixed by replacing “nav_index” with “nav-index”, etc. I updated the example page too.
— Mark ![]()
Your tabs don’t work quite right in Konqueror (the Linux/KDE browser). They seem to be in the right position, but the text inside them seems to start 1 or 2 characters too far right, overflow the tab it’s supposed to be in, then is truncated by the next-to-the-right tab.
What version of Konq are you using? I’m not interested in supporting 2.x, which had wretched CSS support.
— Mark ![]()
It doesn’t work in Opera 7.04 unless I toggle to ‘user mode.’ Author mode is completely blank!
sigh… Your article fits right in with SitePoint at http://www.sitepoint.com/search/search.php?ps=10&q=css&submit=Search (a search on css). They just published an article on pure css rollovers… darn… don’t have the url for you right off…
neato stuff. Opera is strange, isn’t it
— M. Ford ![]()
I tried using lists as tabs a while back, as cleanest, but gave up after the browser-specific workaround list got too long for the technique to be maintainable. I settled for *gasp* tables. Yeah that’s right, and I’ve even convinced myself that it’s semantically more appropriate. I don’t think it’s an obscure pun linking “tab” with “table” – consider tab delimiting as a rough means of representing a table. What’s more, unlike ul/li, table/tr/td/th has a natural candidate for “selected tab” – th. On view:
Proper list mark-up. Ok. What happens if you don’t use lists? Is that invalid or incorrect?
I’m so confused. Following steps in Eric Meyer on CSS – he presents a method sans lists – which has worked for me and I’m using this method… and on some recent sites a hybrid of li tags and sans li…
Is one method more correct than another?
— Marty ![]()
Re: tables. Your linked example appears to be a misuse of the TH element. TH has two purposes: being a header for column of table cells (in which case you would have a row of TH elements, then multiple rows of TD elements), or being a header for the row of table cells (in which case you would have a row with one TH, then multiple TDs). Your example uses TH simply to affect visual styling. You’d be better off simply using TD class=”highlighted”.
— Mark ![]()
If you don’t use list markup, God will strike you down and punish you.
No, really, you should use list markup because what you’re marking up is a list. In previous incarnations of my site, I had the same list along the right-hand side of the page. And guess what: I used list markup, because it was a list. Making it display horizontally doesn’t change the fact that it’s a list.
XHTML 2.0 has a new element specifically for navigation lists. If this site were XHTML 2.0 (ha!) I would use the <nl> element, but in HTML 4 and XHTML 1.x, the best markup available is <ul>.
http://www.w3.org/TR/xhtml2/mod-list.html#sec_10.2.
— Mark ![]()
re: Re: tables: i understand that my usage departs from the normative use cases for th, but i maintain that using th to indicate “selected/active/heading tab” is more accessible (in the commonsense case – not WAI-ish specifically) than loading td or li with private class semantics (selected, highlighted, etc) to indicate a critical distinction. it has little to do with the default rendering of th, which i have modified heavily anyway. the exception is the no-CSS case. the example is visually intelligible in nav2/3/4, while a list is much less so
it would be best if the table didn’t terminate where it does, suggesting the end of the scope of the th. but html is full of examples of stacked structures that we are asked to interpret as nests. a sequence of Hn elements and “children”, for instance.
i like lists for lists, btw. note that the navigation elements along the side are lists – with dt standing in for “label” until we see nl/label et al.
The default visual rendering of TH elements has no bearing on whether you are using them correctly. Also, overloading words like “accessible”, which have specific technical meanings, is a pet peeve of me. Especially here, when the choice of markup actually has consequences for accessibility (in the WCAG sense).
Layout tables in general are clumsy to navigate in screen readers, and display poorly in text-only browsers.
Tables with improperly mixed TD/TH cells may confuse the screen reader into thinking that this is a data table instead of a layout table (which has a different mode of operation). Note: I have not tested this specifically, so this may not actually be a problem, but I *believe* that JAWS goes into data table mode the minute it sees a TH element.
Consecutive <a> tags with no text between them read poorly in screen readers (especially Home Page Reader, which simply reads links in an alternate voice, without any pause or spoken indication that a new link is starting), and display poorly in text-only browsers (where, unsurprisingly, they are displayed strung together without any space between them).
Real lists read well in screen readers (some announce the start of a list and how many items it contains, and they pause a natural amount between list items) and display well in text-only browsers (which generally put each list item on a separate line preceded by an asterisk, as you might type yourself in a plain-text email or other text-only context).
Markup matters. If you only care about visual design, try Flash.
— Mark ![]()
I was just going to ask about what difference does it make if I used lists for my navigation or not. You just answered. Thanks.
— Marty ![]()
Marty,
Just about everything can be a list, just as just about everything can be a table. A document is a list of paragraphs. A paragraph can be a list of spans encompassing each sentence. Ad nauseum.
It’s all shades of grey.
I personally prefer lists for nav links, and Mark’s outlined his (good) reasons for preferring lists.
XHTML2 includes nl, which is an element specifically for a navigation list, and we might expect this list to be used a lot for nav links… but I also expect its “purity” to be subverted as the teeming masses (that’s us) use it for things that it’s useful for.
http://www.w3.org/TR/xhtml2/mod-list.html#edef_list_nl
The degree of subversion is directly related to the lack of tool support, the complexity of the standard, and the variety of people attempting to use the standard.
This subversion of purity, and therefore diluted utility of “semantics”, will continue as long as people must hand-code, or while the standards they attempt to code are too complicated to understand in their entirity easily.
And that looks to be a long while yet.
Also, mu.
http://diveintomark.org/archives/2003/01/15/markup_mu.html
— Mark ![]()
Why are you using the body class to highlight the active tab?
It seems like a nice idea and it works well, but to me it seems much more appropriate to embed the <a> tags in, say, a <strong> tag.
By doing this, your markup says something about the tab currently active. Users which are unable to apply a given stylesheet can still see the difference.
— Martijn ![]()
That’s a good point and I’ll consider it. The real answer is that I’m using server-side includes to include the navbar, so it’s going to be the same for every page. There are lots of other clues on the page as to what section you’re in (page title, breadcrumb trails, H2 tags).
— Mark ![]()
Dumb question. Why <ul> instead of <ol>? A links list strikes me as ordered, at least to some extent (e.g. “Home” is pretty much always the first link). Is it because <ol> implies some sort of ordering marker (numbers, letters, etc)?
I admit this question came up because I was working through Cheetah templates in my head and determined that I’d better represent my navbars as Python lists rather than Python dictionaries. Kinda need that ordering. :)
“and display poorly in text-only browsers (where, unsurprisingly, they are displayed strung together without any space between them)”: Not really, no. See links 25 and 26 adjacent in screenshots below from
http://home.clara.net/ianlloyd/blog/2003_03_01_archive.htm#200035758
http://joeclark.org/aaLynx.jpg
http://joeclark.org/aaLinks.jpg
http://joeclark.org/aaW3M.jpg
(First two examples with link enumeration turned on. Don’t leave home without it. W3M lets you tab to links, which are underlined when active.)
The sequence <a></a><a></a><a></a> is programmatically unambiguous, and any device that can’t make that sequence usable is misrendering standard HTML.
Re: UL vs. OL. Amazingly, I don’t have a strong opinion either way. My instinct says that this list does not have a natural ordering (other than home being logically first). For instance, I’m not suggesting that you visit about before archives, or archives before projects.
If someone wants to make a case for OL over UL, I am certainly open to changing it.
— Mark ![]()
Re: “programmatically unambiguous”. Plain text is programmatically unambiguous, but we use markup because it has advantages. Proper markup has even more advantages. List markup, in this case, has specific advantages over non-list markup in many situations — including in a text browser in the default configuration (without link numbering).
I do, however, agree with your general point that assistive technology should handle the degraded markup better. They should do lots of things better. All browsers should do everything better. IE 5 should have gotten the box model right, but it didn’t. JAWS should support aural stylesheets, but it doesn’t. Maybe link numbering should be on by default in Lynx, but it isn’t.
— Mark ![]()
RE: #37
I thought of the extra complexity you get when using a <strong> tag for an active tab (list-item) after submitting my post. But that’s a maintainer’s issue.
After giving this approach some more thought, I’m not sure if you actually *want* to highlight the active tab in your markup. You can think about the navigation as being a static part of the application, and not as a part of the real content. In that case, I think it would be a styling issue to highlight the active tab, so it would be a good thing to do this by using CSS only (your approach using the body class).
It’s a thin line, and I’m not sure which side to choose.
And, of course, you’re absolutely right there are plenty of other hints to not be confused about your current ‘location’.
RE: UL vs. OL
I can’t think of a better unordered list example than the navigation items on this site. I really don’t see an obvious ordering in them. So an UL would deffinately fit here.
An ordered list would be appropriate for a list of previous postings as you see in many weblog navigation bars. The ordering in this case will be the time of publicing.
— Martijn ![]()
My take on tabs.
http://homepage.ntlworld.com/jared.williams/css-discuss/tabs.htm
Thou Opera doesnt seem to quite get it right.
— Ren ![]()
Opera doesn’t like the negative top value for the tabs. Just hiding that will show the tabs in the expected position in Opera 7. I haven’t checked older versions.
Why is the negative top value needed in the first place? The containing DIV with the background should enclose the tabs, as there is a clearing element beneath them. Maybe I’m missing something ;)
Yes, I know what it takes to get it to work in Opera 7 (it’s still in my testing regimen — for now), but doing that breaks every single other browser on Earth. (Try it. I did.) At which point, I frankly don’t care whether Opera is “right”, because it’s lost the popularity contest with 4 other rendering engines that all agree.
— Mark ![]()
While we are talking about CSS tabs, I thought I would throw an attempt I made a while ago into the mix.
http://www.oldstpatsvision.org/
They were a bigger pain than I thought they would be and I am still not enirely happy with them. I’ll look at athe code of some of the other examples and see if I can come up with something better. Any comments would be appreciated. The site is maintained by the client with Macromedia’s Contribute, so I can’t promise everything will validate.
We use CSS tabs at UpMyStreet: http://www.upmystreet.com/overview/?l1=bs3+1qp
And I was quite pleased with the CSS tabs I did for Pepys’ Diary: http://www.pepysdiary.com/ (although I didn’t bother with drawing in the “off” tabs).
My immediate reaction is that I would have wanted a little more vertical white space within each tab. Imagine my surprise when I added some top and bottom padding to the anchor tag, and NOTHING happened! Oh well, the wonders of CSS will never cease…
— Nico ![]()
Mark. You’re a bloody genius. What would we do without you?
— irritant ![]()
I’m so relieved to hear you say CSS is hard. I was beginning to worry about myself… thought I had some horrible mental blockage.
— Lisa ![]()
I’m abandoning them, after several months of trying to make them work. non-troppo set a useful “how-to” a while back here
http://nontroppo.org/test/tab1.html
which I modified to make
but I can only get them (like yours) to go in two-out-of-three of IE5.5, IE6 and Opera 7.
— Rich ![]()
Rich, be sure to toss Mozilla, Camino, and Safari into the testing mix. You’re sure to shake out a few more quirks!
— Mark ![]()
I am no longer accepting public comments on this post, but you can use this form to contact me privately. (Your message will not be published.)
§
© 2001–present Mark Pilgrim