Posts from Monday, January 21st, 2008

Structured Timeline

Published 10 years, 8 months ago

I wasn’t going to do it.  It would take too long, draw too much energy and attention.  Too many other things needed to be done first.  But it tasked me.  It tasked me!

So: here’s a browser timeline built out of a table.  I’ll say it now: this does not work in IE6 and IE7.  I’m not sure it’s possible to do, at least not cleanly, given the markup I used.  I’ll explain what I mean in a bit.

In order to structure this data, a table seemed to make the most sense, although even it wasn’t perfect.  There really wasn’t anything that seemed an exact fit, to be honest.  Definition lists didn’t really fit the bill (is a browser defined by its release dates?).  Plain old (un)ordered lists were a little better, but not enough.  In the end I just kind of ran with the idea that time sat on one axis and browsers sat on the other axis—like a table.

Given that decision, I needed to decide exactly how to group the data.  After a moments’ thought, I decided that I wanted to group the release dates by browser instead of by year.  Given the way tables are structured, that means every row corresponds to a browser, each data cell in the row represents a year, and the contents of each cell are the versions released in that year.

So here’s an example of a table row:

<tr title="Internet Explorer for Windows">
<th scope="row">
   <img src="icons/msie.png" alt="Internet Explorer for Windows" />
<td class="y1996"><p title="August 1996">3.0</p></td>
<td class="y1997"><p title="October 1997">4.0</p></td>
<td class="y1998"></td>
<td class="y1999"><p title="March 1999">5.0</p></td>
<td class="y2000"><p title="July 2000">5.5</p></td>
<td class="y2001"><p title="August 2001">6.0</p></td>
<td class="y2002"></td>
<td class="y2003"></td>
<td class="y2004"></td>
<td class="y2005"></td>
<td class="y2006"><p title="October 2007">7.0</p></td>
<td class="y2007"></td>
<td class="y2008"></td>
<th class="end"></th>

(And yes, that’s drawn straight from the example, with no simplification and very minimal formatting.  I really wanted to pare the markup down as far as I could.)

The other choice was to have each row represent a year, and each cell represent a browser.  The non-graphical Wikipedia timeline has each row represent a month, not a year, but same general idea.  I totally understand why the Wikipedia timeline is top-to-bottom: it’s much, much easier to update and have render within the Wikipedia layout.  A new month is a new row in the table.  Easy peasy.  Fair enough, but I’m not here to do what’s easy.

Then there was the question of how to structure the version numbers within each year.  I resisted using ordered lists because in most cells there would be only one version number, and there’s nothing in the world of semantic markup that rubs me the wrong way more than a one-item list.  So I went with paragraphs.  I don’t particularly like that either, but short of inventing my own elements and writing a new DTD to support them, I couldn’t come up with much better.

One thing I’m still uncertain about is my decision to title the dates while having the actual content be only the version numbers.  Would it be better to put the dates into content and wrap distinct elements around the date and version numbers?  I’m honestly not sure.

Anyway, having settled on that structure, I had to answer the question of what to put on which axis in the layout.  Should I put the axis of time across the top, as I did originally; or down the side, as in the non-graphical Wikipedia timeline?  Put another way, should the timeline layout be horizontal or vertical?

I went with horizontal.  For whatever reason, I have a strong preference toward timelines scrolling left-to-right, not top-to-bottom.  Yes, even though it invokes that dread abomination, the horizontal scrollbar.  As it happened, given my structural decision, the same effect occurs even in an “unstyled” state.  If I’m just looking at the table with no author styles applied, I see the browsers down the left and the time across the top, proceeding from past to future from left to right.  That might seem convenient from a final layout point of view, except for the fact that I ended up completely ripping the table apart and, in effect, reassembling it with positioning.  This wouldn’t have been necessary had browsers allowed table cells to become containing blocks when they’re set to position: relative.  But they didn’t.

Frankly, I don’t have room here to go through all of the techniques I used and decisions I made.  Doing so would probably require a very long article, or else a very small book.  I did want to spotlight a few things:

  • In keeping with my desire to minimize the markup, I cut way back on classes.  In fact, the only classes I use indicate which year a cell represents, such as y1999, and end to indicate that a cell is at the end of a row.  (I could have dropped all those classes as well, but chose to keep them for reasons too varied to explain here.)  The paragraphs containing the version numbers, as an example, are completely unclassed, nor do they have IDs.  And yet I was still able to position them appropriately within each year.  How?  Check the markup sample to see if you can figure it out; I’ll give the answer later on.

  • I used ems for the sizing of just about everything, so this should be extremely tolerant of changes in text size.  The icons get a bit weird at extreme deltas, but I’m willing to accept that.  Anyway, we all may have full-zooming browsers within a year or three and will leave text-zooming to history.  The nice thing about using ems here, though, is that no matter which flavor of zooming you have to hand, the timeline will accommodate you.

  • I came across at least two things that were of “is this a bug?” interest.

    1. Assigning position: relative to table cells failed to make them containing blocks for absolutely-positioned descendant elements, as I mentioned before.  Changing their display to block allowed them to be containing blocks, but completely shattered the table layout—elements have to have a display of table-cell to act like table cells.  That makes sense, but the lack of containment when relatively positioning the table cells did not.  Turns out that’s permissible as per CSS2.1: 9.3.1: “The effect of ‘position:relative’ on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption elements is undefined.”  Oh well.

    2. Where two elements overlap and both have :hover styles, only the “topmost” (the element higher up on the Z index) of the two gets its hover styles, at least in the browsers I tested.  The handling of hover styles has been an area of debate in the CSS community for quite a while—the CSS2.1 specification does a remarkable job of defining hovering without ever explaining how it should or shouldn’t work—but this single-event model seems unnecessarily restrictive after all these years.

  • Speaking of bugs, I ran into an apparently insoluble problem with Explorer: its allergies over the combination of display and table markup.  Yes, I know, I built bar graphs out of table markup, and that worked fine (even in IE6).  Not so here.  In fact, I couldn’t even get the table element to generate an element box once I’d positioned most of its descendants and converted them all to display: block.  I mean, no matter what I did, it would not show anything.  No height, no width, no borders, no nothing.  I can’t even figure out what’s happening to the display role of the cells, most of which position but some of which still act like they’re cells.  I think.

    Anyway, I was able to get IE7 to recreate 99% of the layout but couldn’t stop the overlap of the table and the following text (“Sources”, et cetera) without throwing in an extra div after the table and using a CSS hack to set its height in only IE7 so as to force the text below the timeline.  No thank you.  So I took the hacks out.  I admit I’m disappointed this doesn’t work as it should in IE7, but I have to remind myself that the fact that it even got close (and it did) is reason for hope.  And if anyone figures out how to fix the layout problems in IE7 (I tried zooming and relatively positioning the table element; neither worked), please let me know how you did it so I can update the CSS and credit you.

    Were I to change the markup to nested lists or divs or something, I suspect it would all come together just fine in IE7.  Not IE6, though… for reasons I’ll explain momentarily.

    Update: Sam Rayner pointed out that an adjacent-sibling-based rule targeted at IE7 would provide a decent fix for the overlap, so I added it in.  The above commentary still stands, except now we have a way to work around the major oddities.  Thanks, Sam!

  • One of the requests for the original timeline was to have an indication of actual dates and browser names.  Yeah, that’s not going to happen with images.  In this version, I was able to use title attributes to add in that kind of information, revealable in tooltips.  It also seemed like an accessibility win, although I’m not sufficiently expert in that field to know whether titles on things like table rows and paragraphs would really help.

  • Regardless, that’s the answer to the question I posed earlier: instead of using classes, I selected elements based on the contents of their title attributes.  So, for example, I place all of the August releases within their respective years by declaring #timeline p[title~="August"] {left: 62%;}.  For another example, I dropped IDs from the table rows, and used the title information instead.  This is an extra reason why the layout fails in IE6 and earlier: no support for attribute selectors.  I suspect IE6 would do okay with the layout if I’d used classes (and non-table markup) instead, but the goal here was to flex my creative-code side and push the envelope to its edges.  So to speak.

    This approach did make my CSS a bit longer.  Selecting on attribute values can be a longer-winded process than on class names, which tend to be compacted to the point of being cryptic.  On the other hand, using attribute selection allowed the markup to be a lot simpler, which is a benefit when adding browsers and new release data to the timeline.  Which, I should note, is now a whoooole lot easier than when I was scaling down JPGs generated from PNGs that I’d saved out of Keynote after using it to draw the dots and lines and such.

No doubt you’ll have noticed that the structured timeline looks different than the graphical one.  I believe I could have recreated the original’s look, but I kind of like this one better.  It’s more interactive, certainly, and having those descending lines (between the top of the timeline on the release dots) might clutter things up too much when looking for information to hover.  If you get what I’m saying there.

I’ve also considered that it would be possible to do a dependency timeline like the SVG-based timeline available on Wikipedia.  Doing so would require an entirely different markup structure; there, nested ordered lists make all kinds of sense.  Once that’s in place, the rest shouldn’t be terribly challenging to work out.  Tedious, perhaps, but not challenging.  But don’t expect me to do it any time soon: it would take too long, and draw too much energy and attention from other things that need to be done.

  • Published
  • Categorized under CSS
  • 45 responses so far