CSS-Only Sticky Table Headers In Chrome
Asked Answered
S

5

71

I have the following Sass snippet in which I want the <thead> to float as the table scrolls. This works properly in Safari, but not in Chrome Version 58.0.3029.110 (64-bit).

I know that Chrome has had on-again-off-again support for sticky, and currently supports it, but is it final? Is this a Chrome bug or do I need a different solution? (I prefer the CSS approach rather than Javascript because it's more performant.)

.table {
  thead {
    background: white;
    position: sticky;
    top: 0;
    z-index: 10;
  }
}
Showmanship answered 16/5, 2017 at 12:49 Comment(2)
Based on browser support, I'd just use fixed instead of sticky. To my knowledge support isn't 100% yet.Oceanic
Related Chromium Bug: bugs.chromium.org/p/chromium/issues/detail?id=702927Maxon
M
89

position: sticky doesn't work with some table elements (thead/tr) in Chrome. You can move sticky to tds/ths of tr you need to be sticky. Like this:

.table {
  thead tr:nth-child(1) th{
    background: white;
    position: sticky;
    top: 0;
    z-index: 10;
  }
}

Also this will work.

.table {
    position: sticky;
    top: 0;
    z-index: 10;
}

You can move header to separate layout. For example:

<table class="table">
    <thead>
    <tr>
        <th>1</th>
        <th>2</th>
        <th>3</th>
        <th>4</th>
    </tr>
    </thead>
</table>
<table>
    <tbody>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
    </tr>
</table>
Mcclinton answered 16/5, 2017 at 14:20 Comment(7)
the separate layout option is only viable if the columns are all the same widthBuckjump
Worth noting that this won't work if the table is contained inside an element with overflow: auto or overflow-x: auto. This occurs if you wrap a table in bootstrap's .table-responsive class.Osburn
I agree with Rick Viscomi about the separate layout option is only viable if the columns are all the same width and also that solution is not without drawbacks if after the table there is other content because the sticky table for the whole content even after the end of the second table with the content, so it is unusable in most situations. It is possible to see an example on jfiddle at the following address: jsfiddle.net/eg6s4097/1 with all mentioned drawbacksGambeson
Well how do you deal with an issue where border stays in place?Katleen
@CBarr I am running into this exact issue. Do you have any solutions if you need to wrap it in a table-responsive class?Pteranodon
@Pteranodon That's the big problem. You may find a suitable solution here: uxdesign.cc/position-stuck-96c9f55d9526... but then again, maybe not.Loewi
You can add position: sticky directly to thead in Chrome now.Pentagon
S
43

For somebody, who is still looking for a solution and isn't satisfied with the accepted one.

1) Use sticky-top class on th element.

2) With own class

th.sticky-header {
  position: sticky;
  top: 0;
  z-index: 10;
  /*To not have transparent background.
  background-color: white;*/
}
<table class="table">
  <thead>
    <tr>
      <th class="sticky-header">1</th>
      <th class="sticky-header">2</th>
      <th class="sticky-header">3</th>
      <th class="sticky-header">4</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
    </tr>
  </tbody>
</table>
Sunbow answered 27/3, 2018 at 10:38 Comment(3)
What about if there are two (or more) header rows in thead?Onesided
@Onesided add a class on second thead with 'top' property set to the height of the first header. This is not dynamic, you have to know the height of your first thead.Hortense
Thank you! As Cbarr said: "Worth noting that this won't work if the table is contained inside an element with overflow: auto or overflow-x: auto. This occurs if you wrap a table in bootstrap's .table-responsive class." this was my case and your answer Tomsgu solved this!Spurrier
K
8

You set the sticky position on the header table-cell instead of table-row.

.td.header {
  position: sticky;
  top:0px;
}

Check out this jsfiddle for simple example.

Kareykari answered 16/7, 2019 at 17:7 Comment(0)
I
1

https://jsfiddle.net/y9cwnb81/4/

div.table {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr auto;

  grid-template-areas:
    "header header header"
    "content content content";
}

.header {
  grid: 1fr/1fr;
}

.content {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: auto;
  grid-area: content;
  height: 200px;
  overflow-y: scroll;
}

.content div {
  grid: auto-flow 1fr / repeat(auto-fill);
}

<!-- Here is the table code -->

<div class="table">
  <div class="header">Name</div>
  <div class="header">Color</div>
  <div class="header">Description</div>
  <div class="content">
    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd,mas, da,msnd asndm,asndm,asndbansbdansmbdmnasbd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>

    <div>Apple</div>
    <div>Red</div>
    <div>These are red asd.</div>
  </div>
</div>

Here is an example using CSS GRID to have sticky headers only with CSS, no javascript required.

Impanel answered 2/10, 2017 at 10:48 Comment(2)
This is a grid with a fixed height and "overflow-y: scroll". It's not using "position: sticky" (so the headers don't "stick" to the top of the viewport). Nevertheless, it's a useful answer that could be adapted to use "position: sticky". Thanks!Fruit
This doesnt work as intended since the header is also fixed in the horizontal directionElbert
S
0

The below should do the trick

table>thead {
  position: sticky;
  top: 0;
  background: white;
}
<table>
  <thead>
    <tr>
      <th>#</th>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Username</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
  </tbody>
  <table>
Shirt answered 2/4 at 11:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.