Skip to Content

CSS / JS Coding challenge

You know how you can have fixed rows and columns in a spreadsheet? So that when you scroll up/down, the fixed columns (aka row headers) scroll with you, but stay in place when you scroll left/right. And the fixed rows (aka column headers) stay in place when you scroll up/down, but scroll when you move left/right. Well, try to make that happen in a web page using native HTML, CSS, and JavaScript.

I've been fighting for the past bit to make that happen. There are a few solutions out there. (Try the Web-Toolkit solution if you only need fixed column headers.) Unfortunately, there are challenges involved all over the place.

First, we have solutions for fixed column headers. There are some that use CSS hacks and/or JavaScript to overcome the cross browser problems. Then there is the column size problem - you pretty much need to define the column widths statically. So much for dynamic content in that case. Then there is the issue of getting the table to NOT squish itself down to fill the available space. And once you overcome all of that, you STILL only have fixed column headers.

For fixed row headers (i.e. the first column is fixed in place relative to the other columns) there are a whole set of other hurdles to overcome. The only solution I can see is to either use a third party control (aka ActiveX which is a BAD solution and only works in IE), or to employ JavaScript.

So, for the past few days I have begun building a custom jQuery plugin that will do both the column and row headers for me. I've had some success, but lots of work to clean this up. I'm not blogging about this to release the plugin - I don't think it's ready for that yet. But I'm taking a break from some of the frustrations I've encountered.

If you'd like to take a look (or better yet, help out), you can see the plugin at http://grover.open2space.com/files/dev/fixedheader/jquery.fixedTableHead.... And a sample of the plugin in action at http://grover.open2space.com/files/dev/fixedheader/plugin2.htm.

Disclaimer: This is development code, so the links may not be there overly long...

The approach I took is that we should ONLY need to declare our table, then tell it that we want fixed headers/footers/row titles by applying the plugin to it. The plugin does a number of things:

  1. Creates a "working" DIV surrounding our table.
  2. Creates a "column header DIV" before the table (but within our "working" DIV).
  3. Creates a "row header DIV" - if needed before the table, and floats it to the left (float: left; in CSS). This is added before the table, but after the column header DIV.
  4. Creats a "footer DIV" after the table, but within our "working" DIV.
  5. A "table DIV" is created around the table. This DIV will do the scrolling.
  6. Looks for a THEAD section of the table. If found it converts the TH contents into a TD cell in the column header DIV. (I found out the hard way that using a TH cell caused grief with sizing the cell properly). The THEAD section is then hidden.
  7. If a number of columns is specified for a row header, then those columns are copied into the row header DIV, and the original columns are hidden.
  8. If a TFOOT section is available, we create a footer from that data. If not, and we have specified the "forceFooter" parameter to the plugin, then the column headers are duplicated in the footer.
  9. The appropriate CSS settings are applied to position and size everything so it all lines up. There's actually a LOT to consider here - border sizes, padding settings, margins, font-sizes, etc.
  10. The appropriate CSS is applied to make the table DIV scroll vertically/horizontally (i.e. overflow: auto; )
  11. An event handler is added for the scroll event of the table DIV. When this fires, we adjust the scroll positions of the column and row headers, and the footer.
  12. It turns out we need to resize/position our headers if the window is resized at all. So an event handler is added for that.

Phew. That's a lot of steps. Luckily jQuery makes it rather easy. But in some cases we have to dive deeper than jQuery - right to the DOM and look at things like offsetWidth/offsetHeight.

The end result is that it works. Kinda. A single plugin call and I have nice fixed column and row headers on my table. I've even applied this to a production table and it works surprisingly well.

But, there's a catch. There always is. It's name is Internet Explorer. It all works well in Firefox. But in Internet Explorer, the table DIV is appearing BELOW the row header DIV. I still need to figure out this bug, but it's the last one (I hope) before I can move onto other tasks. Of course, my customer wants the app working in IE, so I have no choice... sighs.

Asking around on the jQuery mailing list, or in the #css IRC channel reveals that this type of tool is a "it would be nice" type of thing. Meaning that it is not very available. I'm really hoping someone eventually shows me an "easy" way to do this, or an existing tool that does exactly what I need and is well maintained. While it is fun coding the so called "impossible" things, I would really rather not have to maintain something like this. On the otherhand, this could be my shining moment.. Yeah... I'll be a hero to thousands of web developers and they'll all adore me for making their lives easy... Ok, back to reality. My customer needs it, so I'll find a way. That's all there is to it.

Take a look at the existing plugin (currently at version 0.03) and it's sample page. If you can see anything that needs to be fixed, drop me a line. If you can see HOW to fix something, let me know please.. :)