The Table Ruler

Before the days of digital documents and OCR scanning, data entry was a tedious process involving much typing and squinting. You would be handed a huge printout, and asked to type its contents line by tiring line. If you became bored or distracted for even a moment, you could easily lose your place.

Article Continues Below

But you were clever. You got hold of a big old metal ruler, placed it on top of the printout, and moved it down each time you finished typing a row, to remind you where you were and what you had already typed.

One ruler to help us not get stuck#section2

With a bit of JavaScript / DOM sorcery, we can provide our visitors with the same
functionality for long data tables in HTML, by applying rollover states to the
rows. This could be implemented tediously by hand, of course, but it would be silly to do so. Instead, we will use the DOM to find the rows to highlight on mouseover.

Before we proceed, see the effect in action.

Meet the markup#section3

To avoid the script highlighting every table in the document, we
need to tell it which tables to add the ruler to and which not to. We do this by
giving the tables in question a class with the name “ruler.” Next thing
we need to avoid is rows in the table header and the table footer to be highlighted.

Let’s take a look at a demo table:


<table class="ruler" summary="Table of my records">
<caption>My Records</caption>
<thead>
  <tr>
    <th scope="col">Artist</th>
    <th scope="col">Title</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>Ladytron</td>
    <td>604</td>
  </tr>
    [... more content rows here ....]</tbody>
<tfoot>
  <tr>
    <td colspan="2">Last updated: 17.03.2004</td>
  </tr>
</tfoot>
</table>

And the script to apply the ruler:

function tableruler()
{
 if (document.getElementById &&» 
  document.createTextNode)
  {
   var tables=document.getElementsByTagName»
    ('table');
   for (var i=0;i<tables.length;i++)
   {
    if(tables[i].className=='ruler')
    {
     var trs=tables[i].getElementsByTagName('tr');
     for(var j=0;j<trs.length;j++)
     {
      if(trs[j].parentNode.nodeName=='TBODY'»
       && trs[j].parentNode.nodeName!='TFOOT')
       {
       trs[j].onmouseover=function(){this.»
        className='ruled';return false}
       trs[j].onmouseout=function(){this.»
        className='';return false}
     }
    }
   }
  }
 }
}

First, we check to see if the browser supports the DOM; then we get all tables in the
document, and loop through them.

We check to see if the name of the table class is “ruler.” If it isn’t, we skip it and proceed to the next table.

If it is, we take all the table rows and loop through them.

We check to see if the node above the current one is a TBODY (not a TFOOT or THEAD); if it is, we apply a function on mouseover that changes the row’s class name to “ruled.”

Then we wipe the class name clean on mouse-out.

Styling the ruler#section4

To control the effect, all you need to define in
your style sheet is a class for the ruler:

tr.ruled{
 background:#9cf;
}    

These settings will be applied to every highlighted row inside every table
with the class “ruler.”

If you want to have different rulers for different tables, simply give the
table an ID:

<table class="ruler" id="mytable" summary="Table of my records">

and in the CSS:

#mytable tr.ruled{
 background:#333;
 color:#ccc;
}

That’s all there is to it. May your rule be long and happy.

97 Reader Comments

  1. In my case I had alternating background colors on the rows already. I had to make this modification to keep those alternating colors when the mouseout fired.

    // Declare a public variable to remember the style

    var oldRowStyle

    // use this code instead
    trs[j].onmouseover=function(){oldRowStyle = this.className; this.className=’ruled’;return false}
    trs[j].onmouseout=function(){this.className = oldRowStyle; return false}

  2. This is a great article, implementing this technique on any table is a trivial matter. Other than adding the class name to my table, the lack of HTML altering makes this technique the best I’ve seen for highlighting table rows (with IE-friendly behavior).

    Is there any way to correct the problem of IE hiding part of my document when the hover action occurs? In IE6, when a row becomes highlighted other text in my page (any

  3. I went to Position Is Everything once again and re-read their article on this subject:
    http://www.positioniseverything.net/explorer/peekaboo.html
    Which discusses some possible work-arounds.
    I found that putting position:relative in my two floats and on the float container fixed the problem partially, but created more visual problems that didn’t justify using this technique. I’m not going to give an absolute width to the content div (another possible fix), so IE6 folks will have to deal with disappearing text.
    I showed this bug to somebody, and they thought it was a *feature*. Hiding content the visitor currently wasn’t viewing… that’s what I’ll call it, A Feature custom for IE6 users!

  4. >>so IE6 folks will have to deal with disappearing text.<< Maybe I wasn't wrong about ALA being an "idiot magnet". April fools! Really though, a remark like that is translated to me as: "I am too lazy to solve a bug that appears in 95% of the time because that browser sucks". By doing stuff like that you're punishing the user for using IE6. Why do you want to do that?

  5. I found solution to my problem, however it only introduces new problems. I’m not sure if the trade-off is worth it or not, and with further debugging I may be able to find an adequate solution.
    The whole point of my comment was to get feedback on this issue, possibly others who have seen this and dealt with it accordingly. For me, it’s part of the entire debugging process and I find it very useful.

    Take these two pages for example.
    Initial page, with disappearing text problem:
    http://eprojectlog.com/jkf/links/

    Attempt to fix the issue with IE6:
    http://eprojectlog.com/jkf/links/attempt1.php

    This second link does correct the problem, but notice the difference in the behavior of the links in the right column, under the section “Donate” and “Mailing List”. Compare the behavior in these sections to the first link.

  6. “I still don’t see the point in several classes, when you can add in ID and a contextual selector?”

    How about using different class token for alternate rows?

    As you are probably aware, nth-child are not supported in IE. What guys like to do to get that functionality use use a class for alternate rows.




    Then you can have a combined class selector so you can get a different state for alternate rows.

    tr.alternate.hover, {

    }

    tr.hover {

    }

    The javascript required to remove a class is a little trickier. There’s two ways to do it, really.

    I’d be happy to explain it.

    Are you interested on seeing an ALA article on working with multiple classNames in JavaScript? Write to ALA. I’ll be happy to provide, if they’ll have me.

    http://www.alistapart.com/contact/

  7. Sounds great to me. 🙂

    I mean, really, Safari, Mozilla, and Opera users get “punished” so often by buggy code that only works with IE. I’m all for interoperability where feasibly, but if something can work substantially more cleanly with code that basically everything but IE supports, I’m all for it.

    Having said that, I think if sites are developed to use advanced CSS and “degrade” to IE when necessary (using, alas, browser sniffing), users can take notice of stuff like that and do sometimes find in that an incentive to upgrade.

    Me, I can’t see why any web developer would want to work without Javascript Console and DOM Inspector. Lifesavers.

  8. There’s clearly mixed opinions about the script from the foregoing comments, but even so I thought this was really nice code. I’m well-versed in regular JS but just a noob at DOM scripting, and this example isn’t just useful for work, it was helpful to learn from. Code that’s easy to understand like this is the sign of someone who really knows what they are doing. Excellent piece, Christian – thanks!

  9. Ian, Haven’t been around Brinkster in some time, been having so much fun with CSS and web standards that I haven’t touched ASP/ASP.NET in a while.

    Great article indeed, simple approach and very effective. It’s the “Look Ma, I’m not touching HTML!” technique, nothing better.

  10. The same ID “mytable” is used twice in the example on two different tables within the same page. This is not valid. Please correct it.

  11. Of course, this requires inline onmouseover and onmouseout, as opposed to a global onload…however, it does not need to detect DOM type (works in DOM browsers anyways) and can work on any element at all…anywhere.



    Untitled


    test test2


    Much simpler…

  12. Different yes, not so sure it is any simpler. If anything, this article shows a more advanced method of accomplishing the same thing. Sure makes implementation a snap.

  13. Why not just give every table you want the effect with a custom attribute?


    The script will search for all tables with the hover attribute and when the user hovers on a TR the background color will be the value of hover. Simple and easy.

  14. i’m getting a Line 37 Char 28 Object expected error.

    All i did was copy and paste the html, css, and javascript.

    Thoughts?

    Thanks,
    Nico

  15. I have just completed a calendar project that needed this very feature. I opted out for the quick’n dirty by doing a document.getElementsByTagName(‘tr’) and then a onmouseover function with this.style.backgroundImage = “url(calendar_pics/yellowbg.gif).
    I used a dithered background image so the background colour of the table row would still show (rows are color-coded).
    A vertical version is triggered when the user clicks on a month table-header (multiple columns can be selected).
    The table was marked-up using the ‘headers’ attribute for table cells so it was fairly routine to highlight cells that matched the id of the table header to the ‘headers’ attribute of the tds. All works in IE, Mozilla , Opera and Safari.

  16. Thanks for participating so much here, I just came back from a quick trip to denmark, hence no answers until now.

    Nico, without a link to your example we cannot help you, the examples work here, seems you added something wrong. I will set up a live site with some of the changes and fixes shown here, as I cannot reach the ALA hosted site 🙂

    As to some of the “simple” solutions posted here: There are oh so many different ways to reach this same effect, but I consider neither custom attributes nor inline event calls a good solution.

    Custom attributes just add to more problems for inexperienced (x)HTML scripters. Let’s face it, in the world of generated code by blind editors it is hard enough to find clean code in big projects, a lot of developers don’t even bother scripting the current HTML correctly, when it works in forgivable browsers. Why add a non-standard attribute when ID and class do fine?

    The same goes for inline event calls, they are simply unclean scripting IMHO. Why should I add to the document for every TR when I can achieve the same in a javascript loop or a custom event call? It just adds unneccessary page weight and makes me dependent on the markup. The script as it is (with some of the aforementioned changes – multiple classes for example) can work with any clean markup, hand coded, from a CMS output or a database call.

    For all the people adding links here: Please make sure they work, and tell a bit about them, the multiple class one for example was rather useless, a link to the w3c standards would have made more sense. Please keep it on topic. Same goes for IE vs. other browsers, this is pure evangelism and not for here.

  17. When copy/pasting the JS, make sure to remove the line continuation character and move the lines continued text up to its original position.

    Chris, my sentiments exactly only couldn’t have put it so concise. XHTML strict compliancy is desired, after all.

  18. Is it possible to use the ruler method but somehow mark certain cells to NOT have any mousover effect? Say, for instance, a table that has one cell with a rowspan of multiple rows. I don’t want the “spanning” td to change on mouseover, but I would like the ruler to apply to the other td’s in that row.

  19. I apologize for such a simple question. I realize now that all I needed to do was specify a specific class and default css rule to the cell in question and let inheritance (or lack thereof) override any change made by the script.

  20. I chose custom attributes because:
    1. I never ever use DOCTYPES in my pages (so sue me)
    2. Using a class or Id would be “semantically incorrect”. That’s not what classes and IDs are used for, to relay script data. Besides, you can have simpler code and it’s just easier.
    hovercolor=”#eee”
    is only an extra 21 characters towards the total HTML source. I don’t find that really bloating up the code.
    Now using list items for navigation and every single sort of list would be bloating the code, but let’s not get into that.

  21. Sometimes I do wonder why you here Dante. You do seem to hate everything it stands for 😉

    As to the article, while I understand it presents an alternative method, I’d rather just use the IE-Hover behaviour if I’m going to be using JS to hack around IE’s issues.

    Seems a more elegant solution to me, rather than re-inventing the wheel as this article does.

  22. darkcryst: agreed it is easier, but not as customisable. As stated here before, there are loads of ways to achieve this, all with their pros and cons.

    Dante: using no doctype means not writing HTML, you need a doctype to make it a parseable document and avoid quirksmode/standard mode issues. When you don’t use one, you are at the mercy of browsers to guess what they should display, and any browser that has a bit of pride should display your pages as text. You can use custom attributes, and have a valid document, all you need to do is to define them. IMHO too much hassle.

  23. You’re doing such a tremendous job of keeping me entertained across this thread and others.

    As somebody who takes pride in learning and writing valid, semantically correct XHTML and CSS by hand – after all, it’s the blind editing of the Dreamweavers and Frontpages of the world that only help to get muppets like you online – I find it to be massively offensive that you wade in here with rarely a useful comment to make chastising all of us for our opinions and practices when you don’t even bother to TRY and do things properly yourself!

    If you are even remotely serious about your role as a web designer/developer/programmer/whatever then valid, clean markup is essential, Doctypes are a requirement not an option, IE is truly awful but must be catered for, the list goes on.

    Come back and moan at us for being ridiculous for using semantics or wishing IE dea when you start writing XHTML 1.0 Strict – it’s honestly not that difficult.

  24. Chris – I guess that was my point about the alternative method.

    While I think that it is a tad pointless and inelegant to use this method as its shown in this example, it could be a valuable springboard.

    Exactly what AListApart should be really, not how-to’s. So.. you know, great.

    Shakey – wow… venom there. I agree with the general sentiment of “huh?” reguarding Dante, and you are right, XHTML and CSS isn’t that hard, he just choses not to use it right.

    His loss, long term.

  25. As you have painstakingly told me.
    1. I have never used FrontPage or Dreamweaver or any soft of WYSIWYG editor to create websites. Nor am I a muppet. Notepad is fine for me.
    2. Please don’t berate me for taking an alternative approach to web development. That is really immature.
    3. Just a question about the script – Why return false on the mouseovers? There isn’t a need for it, is there? Enlighten me.
    4. About IE – Most people only use it because they know of no other alternative. I myself display a “Get Firefox” sticker on my site. Eventually I’ll make Firefox my main browser, but MyIE2 is just too good to leave.
    5. I tried to give an idea: using custom attributes. If I remember someone yelled at me for not being open-minded. Couldn’t you at least consider some sort of approach?
    6. Explain to me how my CSS isn’t used right. My CSS would be 100% valid except that the validator has a bug when it encounters -moz-box-sizing: border-box.
    7. XHTML Strict? Been there done that. Tried it, didn’t like it. I like to use Capital tags sometimes.
    8. Doctypes are required? I really don’t mean to be rude, but if you want to use DOCTYPES, go ahead. I might start using them later. I’m in no hurry. It’s my website, and I’ll code as I wish, as long as it works in as many browsers as possible.
    Now, back to the article…

  26. > Doctypes are required? … as long
    > as it works in as many browsers
    > as possible.

    http://www.alistapart.com/articles/doctype/

    You offer no real excuse for not including the DOCTYPE declaration, it’s a simple copy/paste and does not cause page rendering problems.
    Try the HTML 4.0 Strict DOCTYPE, it’s quite forgiving.

    Maybe you’re just saying this to get a rise out of us? It seems quite odd to be concerned about XHTML compliancy, heavy CSS usage, yet claim the use of a DOCTYPE declaration is overkill and unnessasary.

  27. Although I do a lot of things to purposely piss hellbent standards people on my site, removing DOCTYPES is not one of them. The real reason goes back to 2003 when I was extremely anti-standards. Since my editor automatically inserts a DOCTPYE (HTML 4 Transitional), the first thing I did when writing a new page was to remove it. “Screw WaSP” I used to say. Now it’s like a habit I can’t break. Always ditch DOCTYPE. I’m trying to break it, but subconsciously I remove it. I don’t really do it to piss anyone off.

  28. But then, I was never into hairbands 🙂

    Pointless discussion here. I don’t care if you have a habit of praying to bricks, just to be different, or type your web sites with 3 toes to see if you can, fact is that this has nothing to do with this article (advocating CSS and DOM and giving away the benefit of standard mode is a contradiction in terms, but we get used to that).

    The return false was force of habit, I do that for the onclick and onkeypress ones, hence it slipped into the onmouseover. I don’t see any justification for them other than maybe overruling inline onmouseover calls (which may not work on all browsers), so you _can_ happily remove them. They don’t hurt though whereas a missing doctype does.

  29. … is to use no Javascript at all. Don’t get me wrong, Javascript is great and all that, but this is a solution that already has an end-to-end CSS implementation.

    Given a table row as follows:

    Column 1 Column 2 Column 3

    You can apply CSS as follows:

    tr:hover td
    {
    background-color: #fcf6ed;
    }

    you can also get a bit clever and add borders:
    tr:hover td:first-child
    {
    border-left: 1px solid #f90;
    }
    tr:hover td:last-child
    {
    border-right: 1px solid #f90;
    }
    tr:hover td
    {
    border-top: 1px solid #f90;
    border-bottom: 1px solid #f90;
    background-color: #fcf6ed;
    }

    Caveat: this won’t work for now on IE – it doesn’t support tr:hover or td:first|last-child. But I’ve got a sneaking suspicion that Dean Edwards’ current endeavor might make that possible. In any case, it does work on recent mozilla releases and if MS ever decides to make IE standards-compliant, it’ll work there too.

  30. We should enforce the same rules as the CSS/Email article discussion has: good grammar only.
    Michael has to leave because he used “it’s” where it should read “its”.
    Oh and using a DOCTYPE does cause a bit of harm on IE6. I don’t wanna take any chances.
    Is Michael implying I’m a troll? OMG that is *so* the Exploring Footers article discussion.

  31. Causes harm in IE6? Do explain, because I’ve found IE6 quite evil when I leave one _out_.

  32. Dear Chris,

    I believe a few other people asked about multiple classes before I did. Now you’re complaining about my link when I’m just filling in the blanks that you left out.

    The discussion on multiple classes has a lot of other comments between. Here’s a recap:

    You said: “I still don’t see the point in several classes, when you can add in ID and a contextual selector?”

    My reply:
    How about using different class token for alternate rows?

    You said:
    the multiple class one for example was rather useless

    You said:
    The script as it is (with some of the aforementioned changes – multiple classes for example) can work with any clean markup, hand coded, from a CMS output or a database call.

    Now we get the truth out. That’s why I posted the link, and if you’d read the page more thoroughly before making denigrating statements, you’d see there’s a lot of information that the w3c spec doesn’t include. The page links to the HTML and CSS 2 TRs.

    To be honest, your example is not really useful in and of itsself, though it could be useful in an application. However, thin client application developers should be able to do this stuff in his sleep.

  33. I am still a novice at this and a lot of the posts above confused me . However, I wanted to say a massive thanks to Chris, I have just put the ruler on my site and I think its looks great.

    Thanks

    Ant

  34. Hey guys;

    Great idea here; I have modified the code to stop it clobbering existing classes on the TRs – it still clobbers the onmouseover/out though. Thought someone might like this:

    function tableruler()
    {
    if (document.getElementById && document.createTextNode)
    {
    var tables=document.getElementsByTagName(‘table’);
    for (var i=0;i= 0)
    {
    var trs=tables[i].getElementsByTagName(‘tr’);
    for(var j=0;j= 0)
    {
    this.className = this.className.substring(0, this.className.length – ruledClass.length);
    }
    return false;
    }
    }
    }
    }
    }
    }
    }

  35. NUM NOMBRE APELLIDO
    1. Marc Palau
    2. Marc Palau
    3. Marc Palau
    4. Marc Palau

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career