We can get a simple tree structure in html by using nested lists. While this gives us the basic structure, it doesn't provide the desired graphical linking, so we need do something else. We could rewrite the HTML, but since this is the logical ordering of a tree, we want to use the nested lists so that the document still makes sense for those who may be "viewing" it without the fancy presentation (such as those using screen readers or otherwise) — Enter CSS.
For a better general tree example see A Simply Styled HTML Tree— it only works in Mozilla; it appears that IE has a problem rendering relative positioning on unordered lists (using IE, check out the example page without the relative positioning to see what I mean). If anyone is aware of a problem (with my CSS or IE) please let me know.
To make the example concrete we'll start by attempting to create a family tree. The
unstyled version looks rather plain, but
gives us the information: John has had four wifes, producing children with each of them,
and is currently involved with a woman by the name of Linda. Below is the
HTML source code for the family tree of John.
<ul id="family-tree">
<li id="root">
<span id="poi">John (Person of Interest)</span>
<ul id="relationships">
<li id="relationship-1" class="marriage">
<span id="spouse-1">Mary (Wife 1)</span>
<ul id="children-1" class="children">
<li><span id="child-1-1">Joe</span></li>
<li><span id="child-1-2">Jack</span></li>
<li class="last"><span id="child-1-3">Jill</span></li>
</ul>
</li>
<li id="relationship-2" class="marriage">
<span id="spouse-2">Jane (Wife 2)</span>
<ul id="children-2" class="children">
<li><span id="child-2-1">Martin</span></li>
<li><span id="child-2-2">Melissa</span></li>
<li class="last"><span id="child-2-3">Matt</span></li>
</ul>
</li>
<li id="relationship-3" class="marriage">
<span id="spouse-3">Jill (Wife 3)</span>
<ul id="children-3" class="children">
<li><span id="child-3-1">Cathy</span></li>
<li class="last"><span id="child-3-2">Karin</span></li>
</ul>
</li>
<li id="relationship-4" class="marriage">
<span id="spouse-4">Kate (Wife 4)</span>
<ul id="children-4" class="children">
<li class="last"><span id="child-4-1">Bill</span></li>
</ul>
</li>
<li id="relationship-5" class="intimate">
<span id="spouse-5">Linda (Girlfriend)</span>
</li>
</ul>
</li>
</ul>
Look closely at the source code -- notice that within the list elements we have
span
elements surronding the text: this is key to the way we're
going to give the tree its visual appearance and because of the use of the
span
elements we won't interfere with the logical list structure.
We start the visual adjustments by removing all the list markers. This is done with the code
ul
{
list-style-type: none;
list-style-image: none;
}
Next we want to remove the padding on the "relationships" list, and give it a margin instead.
The reason for doing this is so that the whole list can be given a left border which will run
completely along the side giving us the "vertical branch". The following CSS accomplishes that:
#relationships
{
margin-left: 40px;
padding: 0;
padding-top: 1.5em;
border-left: 1px solid black;
}
Note that some padding is given on the top so that the left border will go above the first list element allowing the "vertical branch" to be attached to higher levels (in this case we're actually at the root so there aren't higher levels, but it becomes associated with "John").
Now it's time to put on the horizontial lines that will attach to the vertical line we just
added. We're going to do this by giving each <li>
element a
top border
#relationships li
{
width: 150px;
border-top: 1px solid black;
text-align: right;
}
we've also aligned the text to the right for this element so that everything will line up nicely.
It's important that we do the alignment here since these blocks are defined with width and take up
all the visual space where the text can be. The <span>
element
will end up "hugging" its contents (which is want we want it to do anyway), so any alignment
property given to it would not be seen.
There's one more cosmetic thing we need to take care of: since the left border goes from the
top to the very bottom of #relationships
, it hangs below the top border
of the last element. So, to take care of this, we'll give the last
<li>
element a left border the same color as the background of the
list (white), and then push it left by the width of the border -- covering up the undesired extension:
#relationship-5 /* this removes the border from the last li */
{
position: relative;
left: -1px;
border-left: 1px solid white;
}
There. Now we're ready for the neat trick. Since the <span>
elements are there, we can move them around. Specifically, we can move them above their
current position. If we also given them an opaque background, they will sit right on top of the
<li>
's top border line. Since spacing of a line is usually
1.5ems (or 1.5 times the height of the current font) we only need to move the
<span>
's up by half that amount:
#relationships span
{
position: relative;
top: -.75em;
background-color: white;
}
Now we do the same exact procedure for the child list elements:
#relationships ul
{
position: relative;
top: -1.25em;
margin: 0;
margin-left: 40px;
padding: 0;
padding-top: 1.5em;
border-left: 1px solid black;
}
#relationships ul.children li
{
width: 80px;
}
#relationships ul.children li.last /* remove the left border from the last child li */
{
position: relative;
left: -1px;
border-left: 1px solid white;
}
And then just add on some formatting to center the tree and make the person of interest in a
larger font
#family-tree
{
width: 300px;
margin-left: auto;
margin-right: auto;
}
#poi{font-size: 130%;}
The final result is here and has two styles to choose from (in mozilla you can easily switch by going to View->Page Style -- it's not so easy in IE): one where the text is right aligned and the other where it's left aligned. You need to be a little careful about that left alignment though -- the trouble spots have comments in the css file.
Of course, if you want to get really fancy,
that's possible too. The different
colors used in that page are there to indicate what border is being used:
a black border belongs to relationship-rel_num
,
an orange border belongs to children-rel_num
border,
and a red border belongs to the <li>
of
children-rel_num