Rotating Title Headers for Tables

May 4, 2017

One of my co-workers (Jason Giles) and I were recently pairing on the implementation of a table for a client that would allow dynamic addition and removal of rows.  The table would have section headings of rotated titles display across the side of the table.  I will walk through the code that we wrote to rotate the headers below.  Alternatively, you can view a working example on codepen here.

Rotating the title headers with CSS

First, we have a set of CSS rules that rotate the content inside of the div to display vertically.  The last two rules are (optional) formatting applied to title content inside the cell.  These rules are not necessary for pushing the text to display correctly.

.rotate-title { overflow: hidden; text-align: center; transform: translate(-50%, -50%) rotate(-90deg) translate(-50%, 50%) translate(-3px, 0); white-space: nowrap; position: absolute; line-height: 30px; font-size: 0.875em; text-overflow: ellipsis; }

In addition to performing the rotation, the code was written to adjust the heights so that the rotated element takes up the height and width of its container.  The code also needed to apply an ellipsis effect if the content overflowed its container.  The line-height is set to 30 for the JavaScript below.  The first three pieces of the transform are for rotating the text.  The final translation is to push the rotated text back into the center of the rotated container.

Making the table dynamic with JavaScript

The first part of the JavaScript generates css classes to be applied to the elements with the rotate-title class.  CSS is a lot faster than reprocessing all of the elements in the JavaScript (which was causing a performance bottleneck in FireFox).

var style = document.createElement(‘style’); style.type = ‘text/css’; for (var i = 1; i <= 100; i++) { style.innerHTML += ‘.rotate-title-span-‘ + i + ‘{width:calc(30px * ‘ + i + ‘ – 6px);}’; } document.getElementsByTagName(‘head’)[0].appendChild(style);

The earlier translation by -3px is designed to be half of the 6px that is subtracted from the width (in line 4). This is to account for padding and border height within the line height.  This centers the text in the container and ensures padding around the rotated text.

Applying container size with JavaScript

The second part of the JavaScript creates a function to be dynamically applied while the app is running (and calls it for the first time).  The method will re-assign the CSS class based on the number of rows in a given section (in the codepen example, the rowspan is hard-coded).

$(function() { var recalculateRotatedTitleHeights = function() { $(‘.rotate-title’).each(function(index, elem) { var span = parseInt($(elem).parent().attr(‘rowspan’)); $(elem).removeClass().addClass(‘rotate-title rotate-title-span-‘ + span); }); }; recalculateRotatedTitleHeights(); });

The only thing left to do is to call the recalculateRotatedTitleHeights function from the places in your app where the number of rows in a section are affected.

Dealing with browser display oddities

You may notice if you are pulling this out of the box that it does not display correctly in all browsers.  At the time of writing, several browsers will not correctly display borders between the title blocks when a background is set.  This is due to the way they collapse borders on rows with cells that have a rowspan.  Below is some CSS that corrects the problem when hacked in:

@-moz-document url-prefix() { table.table-separate { border-collapse: separate; border-spacing: 0; } } @supports (-ms-ime-align:auto) { table.table-separate { border-collapse: separate; border-spacing: 0; } } @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { table.table-separate { border-collapse: separate; border-spacing: 0; } }

You can see the quirk at play by commenting out the section for an affected browser (FireFox, Edge, IE) in the CSS on the codepen.