72

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;
  }
}
2
  • 4
    Based on browser support, I'd just use fixed instead of sticky. To my knowledge support isn't 100% yet. Commented May 16, 2017 at 12:56
  • 2
    Related Chromium Bug: bugs.chromium.org/p/chromium/issues/detail?id=702927 Commented Apr 5, 2018 at 15:36

5 Answers 5

91

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>
Sign up to request clarification or add additional context in comments.

7 Comments

the separate layout option is only viable if the columns are all the same width
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.
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 drawbacks
Well how do you deal with an issue where border stays in place?
@CBarr I am running into this exact issue. Do you have any solutions if you need to wrap it in a table-responsive class?
|
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>

3 Comments

What about if there are two (or more) header rows in thead?
@Jivan 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.
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!
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.

Comments

2

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>

1 Comment

I think something must have been fixed recently in chrome/firefox because this works great!
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.

2 Comments

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!
This doesnt work as intended since the header is also fixed in the horizontal direction

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.