css-trees-and-tabs


CSS only sample for creating tabs and expandable trees without javascript

Novel method (so far as the author is aware) of displaying tabs and trees using pure HTML/CSS - no javascript needed.

Works on modern browsers which support html labels, css's :checked property, and css's + selector.


While playing with radio buttons I accidentally discovered that I could use them to make tabs in my web pages without the use of javascript. This has already been done, often with pagename>tabname such that the body tag for each page has id=pagename as an attribute. I'm sure there are other methods too. A quick google search did not reveal the method I had found. A couple more minutes with CSS and I had a tree menu which expanded and collapsed on a click. Cool.

This method is not necessarily better or worse than what's out there. It's just different. I don't really care to debate the finer points of whose tabs are more efficient to run or more elegant to read. This is just another method of doing tabs solely in CSS, without a page refresh. Use it if you like.

As I already mentioned, this method works for modern browsers. It relies on form labels clicks going to the appropriate form input as well as css's :checked property and plus selector. As of this writing, it works in Firefox2 and Opera but not IE7 and I haven't even looked at IE6.


See downloads for code. You'll have to download treetab.html and style.css to the same directory for a working demo.


Here's how css tabs work:

The HTML is straightforward. You have a form. Give it an ID so that your css doesn't clobber other forms in your page. Each tab goes in the form and has three elements. * input * label * div

The input is set to type=radio. This supplies the page with a behavior. When you click on a radio button, it gets checked and all other radio buttons get unchecked.

Labels have a for element that indicates which form input they affect. Each of your labels will point to a radio button. Unlike a traditional table of text - radio button cells, a label can be clicked on to check it's radio button.

Finally the div. This is where the content of each tab lives. Yes, this means your page will load all the tabs and once and can switch between them without page reloads or AJAX calls.

style.css is where the magic happens.

First we hide the tabs. You should either class them to .tab or use #tabform>div to select them. display:none will hide them all.

But tabs that are clicked should be seen. This is where :checked and + come in. :checked will match any radio button that is selected. + is one of those new CSS selectors with a very limited, but occasionally very useful purpose. E + F selects an F which is immediately preceded by an E. So in this case, input[type=radio]:checked + label + div.tab will select an div with class tab, whose predecessors are a label and a checked radio button. Set this div's display to block. Now when you click through the radio buttons different divs are displayed! As the tab divs are set in between the radio buttons, they'll show up in between them. Toss in a float:left to push them below the radio buttons. (Alternatively you could make a row of labels and put your input/tabs elsewhere on the page. This is probably a better way to do things, though it will mean rewriting some selectors.)

Finally we have to disguise the fact that we're using forms. input[type=radio] display:none; will get rid of those pesky circles and leave your clickable labels intact. Now you have working tabs, with no javascripted mess.

You may want to pretty them up a bit though so that they actually look like tabs. I like using the following: input[type=radio]+label to format inactive tabs. I usually give them a 1px solid border.

input[type=radio]:checked+label is the highlighted tab. To make it look like part of the tab it opens, give it a border-bottom-color: white, or whatever color your tab is. You may also have to raise the tab div 1px so it's border gets covered by this white one.

input[type=radio]+label:hover. One problem I've noticed with this method is that tabs give no feedback that they're clickable. You could change the cursor with javascript, but that defeats our no javascript rule. Instead I've been changing the color to blue when hovered over.

div.tab Give your content a border much like the tab border. Again, you may have to position it up a pixel to make the borders overlap.


Making an expanding tree using this method is trivial. I won't go over it in quite as much depth.

Here you want to use checkboxes rather than radio buttons (unless you want sections to collapse when other sections are opened). The big difference here is that I took off the pretty colors and borders and added display:block to input[type=checkbox]+label. This made each label into its own line. I also removed float:left from the tabs so that they would appear between tabs, rather than under them.

Adding expand and close buttons should be trivial. Basically you're going to give each label a background image that doesn't repeat. Unchecked the image will be a - (or whatever you choose for your close button). You'll want to use a small bit of padding left so that the text doesn't flow over the image. Change the image to a + for input[type=checkbox]:checked+label.

Project Information

Labels:
css tabs html nojavascript tree expand