Consistent Dynamic Layout Across Multiple Tables

Not-So-Smart Dummies

It had been a while since I’d done much with tables.  Back in the day, that was how things got done; developers lived, breathed, ate and dreamed of tables.  …but it was never the correct approach.  A new project came along where I needed to display multiple dynamic-width tables with linked layouts, i.e. the columns in table A are always the same width as the ones in table B.

Percentages could work, but they’re awkward and imperfect.  Turning the page into one big table would certainly do the trick, but that’s not at all the right way to do things.  The CSS declaration “visibility: collapse;” seems to be designed exactly for my need (i.e. put the same dummy row in each table and collapse it such that it affects the layout as desired yet isn’t displayed), but as close as I was able to get, some browsers just wouldn’t cooperate.

I really wanted to make it happen with CSS, but in my frustration and under a mandate to get it done quickly, I turned to JavaScript, specifically jQuery, which I’m finding more and more appropriate for difficult layout issues on sites where JS is required anyway.  The outcome is a relatively simple snippet concept that solves a particularly frustrating problem.

The CSS:

table {
    // dynamic-width tables
    width: 100%;
}

The JavaScript:

function smartDummy() {
	// make sure the smartDummy row's visible so you can evaluate its layout
	$("#smartDummy").show();
	// for each cell in the smartDummy row
	$("#smartDummy td").each(function (i) {
		// get the width of this cell
		utilityWidth = $(this).width();
		// establish a selector for the cells that should follow suit
		cellSelector = "tr:not(#smartDummy) td:nth-child(" + (i + 1) + ")";
		// set those cells to the width of the smartDummy cell
		$(cellSelector).css("width", utilityWidth);
		// establish a selector for the corresponding table headings
		headingSelector = "tr th:nth-child(" + (i + 1) + ")";
		// set those headings to the width of the smartDummy cell
		$(headingSelector).css("width", utilityWidth);
	});
	// hide the smartDummy row again
	$("#smartDummy").hide();
}
$(window).load(
    function () {
        // execute the function when the page loads
        smartDummy();
        // execute the function when the window is resized
        $(window).resize(smartDummy);
    }
);

I’d post a section detailing the HTML, but WordPress is refusing to let me put all the content I’d like to within pre-formatted text.  The idea is to in the first of your array of linked tables, add a row with id=”smartDummy”, the contents of which should represent the longest values you’ve provided for displaying in each cell by column.  I generally use the number 8 character for mockup in those cells because in almost every typeface the 8’s one of the widest glyphs.

This effects the desired result without introducing inappropriate semantics – see it working in my demo.  You can fine-tune to provide for multiple arrays, run a single width-assigning line instead of two and/or do any number of things as wanted/needed (for instance I had to support tables that weren’t necessarily visible at the time, out of sight in an accordion), but the basic concept works and works consistently across browsers.  Hope you find this useful.  I know I do.