Highlighting rows of a table is pretty darn easy in CSS. tr:hover { background: yellow; } does well there. But highlighting columns has always been a little trickier, because there is no single HTML element that is parent to table cells in a column. A dash of JavaScript can handle it easily, but Andrew Howe recently emailed me to share a little trick he found on StackOverflow, posted by Matt Walton.

It was a few years old, so I thought I’d just clean it up and post it here.

The trick is using huge pseudo elements on the <td>s, hidden by the table overflow

You don’t really know how big the table is from CSS, so just make the pseudo elements super tall with a negative top value of half of that.

table { overflow: hidden; } tr:hover { background-color: #ffa; } td, th { position: relative; } td:hover::after, th:hover::after { content: ""; position: absolute; background-color: #ffa; left: 0; top: -5000px; height: 10000px; width: 100%; z-index: -1; }

The negative z-index keeps it below the content. Negative z-index is a fun trick, but beware this table then can’t be nested within other elements with backgrounds, otherwise the highlight will go below them.

You can see that in action here:

See the Pen Row and Column Highlighting with CSS Only by Chris Coyier (@chriscoyier) on CodePen.

Making it work with touch

Hover pseudo classes only kinda work on touch devices. First, the element needs to be focusable, which table cells are not by default. You could certainly add a click event handler to the table cells and just do everything in JavaScript, but here’s a method to keep most of the work in CSS:

// Whatever kind of mobile test you wanna do. if (screen.width < 500) { // :hover will trigger also once the cells are focusable // you can use this class to separate things $("body").addClass("nohover"); // Make all the cells focusable $("td, th") .attr("tabindex", "1") // When they are tapped, focus them .on("touchstart", function() { $(this).focus(); }); }

Then in the CSS you add :focus styles as well.

td:focus::after, th:focus::after { content: ''; background-color: lightblue; position: absolute; left: 0; height: 10000px; top: -5000px; width: 100%; z-index: -1; } td:focus::before { background-color: lightblue; content: ''; height: 100%; top: 0; left: -5000px; position: absolute; width: 10000px; z-index: -1; }

In my final demo, I got a little fancier with the CSS selectors ensuring that empty table cells didn’t trigger anything, table headers in the <thead> only selected columns, and table headers in the <tbody> only selected rows.

You can see that in the final demo. And here’s touch working: