jasonkarldavis.com

trees of bees!

CSS Trees

Long has it been established that anyone seeking interactivity on their website immediately assumes that DHTML or Flash are their only options. However, times are changing, and with the abilities CSS2 and CSS3 grants web developers, once arcane pieces of DHTML can be replaced with degradable, accessible markup.

Interested? Read on.

Concept

Exactly what is a tree? It is a way of containing a large amount of "links" in a condensed fashion. They are grouped by category, then by subcategory, etc. Next to "parent links" are images indicating whether or not there is content to expand/collapse (typically + and - signs).

The good folks at WebFX have a beautiful DHTML implementation of such a tree. However, this author believes that Javascript isn't necessary to implement a basic tree.

As a matter of fact, there is only one requirement that is not typical in CSS implementations needed to be fulfilled in order to accomplish this using plain old CSS.

We need to be able to apply the :focus pseudo-class to any element (in this case, <ul> elements).

Implementation

Before we can do anything, we must consider what element is the most appropriate in a tree? Removing our effects, will it still remain accessible? Logically, it seems that <ul> is the best element for the job.

Now, here is the limiting factor: at the time of writing, no web browser supports the :focus pseudo class on an unordered list. However, the CSS3 User Interface module specifies a user-focus property, which reasonably should allow elements to be selected by :focus. (Update - 8/10/03: It seems as though this CSS3 module has been superseded, and user-focus has not found it's way back into the specifications. There is still time for it to be reincorporated though.)

Where does one go for CSS3 support though? Everyone's favorite lizard of course, Mozilla. For some reason or another, the developers partially implemented this property (probably for some UI reason with XUL), and added the vendor-specific prefix as they are supposed to.

Here is the CSS we will use to style and implement the tree:

ul.tree > li {
	-moz-user-focus: normal;
}
ul.tree > li > ul.tree {
	display: none;
	margin-left: 1%;
	padding-left: 1%;
}
ul.tree > li:focus > ul.tree {
	display: block;
}
ul.tree > li {
	color: #000;
	cursor: pointer;
	font: 0.8em Arial,Helvetica,sans-serif;
}
ul.tree > li > a {
	color: #00f;
	text-decoration: none;
}
ul.tree > li > a:hover {
	text-decoration: underline;
}

The first selector makes the list-items focusable, the second hides nested trees, and the third is where the action occurs. It makes a nested list visible again when the list-item is focused.

Example

(Mozilla-only):

The markup:

<ul class="tree">
	<li>Section 1
		<ul class="tree">
			<li><a href="subsection1.html">Subsection 1</a></li>
			<li><a href="subsection2.html">Subsection 2</a></li>
			<li><a href="subsection3.html">Subsection 3</a></li>
			<li><a href="subsection4.html">Subsection 4</a></li>
		</ul>
	</li>
	<li><a href="section2.html">Section 2</a></li>
</ul>

Drawbacks and Limitations

It isn't a perfect implementation yet. The first thing that might be apparent is that the links immediately collapsed after clicking on them, without even activating. I'm 99.9% sure that this is a bug in Mozilla having to do with focus on child nodes. This same issue is also preventing nested trees. When you click to expand a nested tree, the outermost one closes because it "lost focus" - however it didn't really, as now a child node has focus, which should propagate upwards logically. The window has focus because an element inside of it does, so why can't an element have focus if a child element has it?

Minor drawbacks include toggling. When you click an expanded item, you expect it to collapse. Instead, since we are using :focus, it remains open. This is counter-intuitive to any popular graphical OS's behavior, which isn't a good thing.

Another limitation is indicating whether or not there is content to expand. The only way I can think of counteracting this is a non-existant ::parent selector.

There is also the issue of persistence. This method is about as nonconducive towards persistence as you can get it.

And of course, there is one obvious drawback to this approach: Only Gecko-based browers will see it. It downgrades nicely in Internet Explorer for Windows, however Opera and IE5/Mac may end up just seeing the top-level elements and nothing else.

Conclusion

Considering all of the problems associated with this approach, I highly that doubt that it will ever become widespread. By the time CSS3 is standardized and implemented in the majority of web browsers, we may have XHTML 2.0's <nl> element to toy with.

I hope that this article did however provide some insight into the lesser-known abilities of CSS, and what could be possible in the immediate future.

Comments? Interesting links? Send me an email.