sticky table headers with bottom borders

Brian Hicks, November 13, 2023

Say you have a table like this:

      <th>Column 1</th>
      <th>Column 2</th>
      <th>Column 3</th>
    <!-- ... -->

You might try to separate the header from the body like this:

table.fancy > thead > tr {
  border-bottom: 1px solid #ccc;

That works, but what if you want the <thead> element to have position: sticky too? If you used a border, the border will keep scrolling while the header sticks. Oh no!

I got around this by using box-shadow instead. It works, despite feeling a little hacky:

table.fancy > thead > tr {
  box-shadow: inset 0px -1px #ccc;

Except that Safari won't display the shadow below the header. More hacks required! Apply the shadow to all the cells inside it:

table.fancy > thead td {
  box-shadow: inset 0 -1px #ccc;

This feels even hackier than the original fix, but it works fine in all the browsers that I tested!

If you'd like me to email you when I have a new post, sign up below and I'll do exactly that!

If you just have questions about this, or anything I write, please feel free to email me!