The border-collapse
property is great for making borders even all around <table>
cells. It makes for a clean look that I actually prefer.
But, there is something that can cause issues with how a browser draws the cells and their respective borders. Each cell is placed under the previous one when being drawn in order. This means that if tables have different colored borders, those borders are hidden on some sides.
The Problem
In the code example below, hover over cells to see how borders can be hidden behind each other.
See the Pen Table border collapse step 1 by Daniel (@gooseofmusic) on CodePen.
Since z-index
doesn’t work on cells inside a <table>
, we have to work with the content inside the cells.
The Solution
Step 1
Fair warning: this solution will employ the use of negative margins. For those of you who don’t like negative margins, avert your eyes.
First, we put a wrapper around the content inside the cell. Move the border, padding, etc to the inside content to match.
See the Pen Table border collapse step 2 by Daniel (@gooseofmusic) on CodePen.
This alone will actually reverse the problem: the borders on the bottom and right show up on top.
Step 2
From there, we also have to add z-index
to the :hover
state so it stacks above the other elements. Because we’re z-indexing content inside the table cell, rather than the <td>
itself, it works.
See the Pen Table border collapse step 3 by Daniel (@gooseofmusic) on CodePen.
Make sure the z-index
is not included in any transition
or you’ll see the previously hidden borders “swipe” into view rather than fade.
Doesn’t work when hovering fast.
The fade-out has a glitch that isn’t really nice, a better way would be to use a pseudo-element, thus eliminating the need for a div inside each table cell and solving that glitch:
The problem I see here is that any elements on the inside of the cell (such as anchors) cannot receive pointer events as the pseudo-element covers them.
Pointer events could be a solution to this, but it’s not well-supported yet.
You can solve the pointer event issue by giving the td a z-index and the pseudo element a negative z-index (placing it behind the td but in front of the table). I did not test this cross-browser.
Yea… in the case of an anchor or button the styles would need to be moved to them, solving the issue of the pseudo-element obstruction.
Box-shadow as alternative. Nobody will notice the difference and no mogic.
Nice! It looks like the best solution so far.
More often I use box-shadows to create a borders. It gives me much more control than regular borders / outlines. Good point Vitali!
Why not just use the outline property instead with outline offset?
Because the outline doesn’t allow for rounded corners when you need them.