How I fell in (back) in love with tables | NetEngine

How I fell in (back) in love with tables

Brad Tuesday, 4 June 2013

Geocities, has been a concrete part of web folklore for a while now. Everyone of a certain generation comes over all nostalgic at its mention, but there’s one thing in particular Geocities consistently reminds me of: tables.

We all made our layouts with tables and were happy, then CSS happened and it became frowned upon. Once I’d gotten used to floats and various other display and positioning properties I began to loathe tables. They had become confusing and verbose. I didn’t want to see them anywhere. The problem, of course, was that in my table-as-layout-element zeal (Fight) I had never used one for what it was designed for.

Recently I’ve been making my peace and even falling back in love. I’ve spent a lot of time on views that were heavy on tabular data. Perfect, that’s what we need: tables for tabular data (all the semantic brownie points!) More than that though we had a practical problem that the fixed table algorithm solves.

It could be a common problem for you, it certainly was for us. Lists of tabular data that can be ‘scoped’ or filtered mean that at different tiers cetain columns aren’t required. For example in Trigger we have a tiered organisational structure: companies, projects and tasks. Companies have projects and projects have tasks. If we view a list of all our tasks we want to see the company and project for each task. If at another route we are viewing all the tasks within a particular company we no longer need a company column, it’s redundant. The same goes for if we’re viewing a list of tasks within a particular project, we no longer need to see either the company or project columns, they’re both redundant.

Floated or inline-block layouts need explicit widths, if we were to try and use them in this scenario we’d be repeating ourselves and it’d be difficult to maintain. We’d need to keep setting widths every time a column was removed, we’d end up with messy views and overly specific CSS. BOO!

Table layout fixed to the rescue! As the recommendation states:

“The width of the table is then the greater of the value of the 'width’ property for the table element and the sum of the column widths (plus cellspacing or borders). If the table is wider than the columns, the extra space should be distributed over the columns.”

So, we can just set percentage widths for one state for our table - the one where all the columns are present. If we remove columns we don’t have to do anything, the browser will figure it out for us (Chrome and Firefox are nifty enough to recalculate even when our width exceeds 100%).

This is also super handy for responsive tabular data, if certain columns will be less useful to a mobile user - no problem - display: none and the browser does the heavy lifting for us. SWOON!

Before I run through some examples of how we structure our SCSS to make the most of this I’ll get the caveats out of the way. I found some weirdness trying to get separate tables to calculate their widths in exactly the same way. Chrome / Safari had no issue but IE and Firefox did. The solution was to take any horizontal borders and padding out of the equation. In our case internal elements were already available to space things out but I’d have rather padded the cells themselves. It bears further investigation.

On to nerding out about grids

We’ve started using a simple, flexible grid scss mixin for most layout work. it looks like this:

$gutter: 2em;

@mixin col_span( $span, $total ) {

  display: inline-block;
  vertical-align: top;

  width: 100% / $total * $span;
  padding: 0 $gutter / 2;
  @include box-sizing( border-box );

  // This gets around the whitespace put between inline-block elements
  margin-right: -0.25em;

  &:first-child, &.first {
    padding-left: 0;
  }

  &:last-child, &.last {
    padding-right: 0;
  }

}

From here it’s easy to make helpful classes, e.g:

.one_half {
  @include col_span(1, 2);
}

If we were only, or predominantly using it for tables we’d skip the display, vertical-align, box-sizing and margin properties. This makes it super simple:

$gutter: 1em;

@mixin col_span( $span, $total ) {

  width: 100% / $total * $span;
  padding: 0 $gutter / 2;

  &:first-child, &.first {
    padding-left: 0;
  }

  &:last-child, &.last {
    padding-right: 0;
  }

}

You could then make something for complex, fixed tabular layouts:

// 24 column grid for table layouts

@for $i from 1 through 24 {
  .span_#{$i} {
    @include col_span( $i, 24 );
  }
}

table.dynamic_table { table-layout: fixed; }

Hey presto, start applying the classes you need. Make sure that when your table is at it’s fullest all the 'span_’s add up to 24 and there’ll be no more horizontal headaches. It’s hard to convey how happy I was when I’d figured all this out.

HAPPY

Final thoughts

In the end the naming here is funny, tables with layout: auto are not very fluid. They have a minimum size whereas layout: fixed tables are highly responsive, go figure.

Yes, flex box is on it’s way. It won’t be long before it’s standard and helping us to finally mount the seemingly insurmountable: clean, fluid, grid-based layouts. What I’m talking about here is somewhat unrelated, it’s simple: we don’t have to fear, or fight tables. They serve their purpose well, it’s taken me a long time to realise that.

comments powered by Disqus