Ala Soua
Ala Soua

Reputation: 23

HTML table: Sticky column overlapping header

I am trying to implement an HTML table that could have a sticky column(s) and a sticky header at the same time, using javascript and css.

Basically I am trying to ensure the stickiness of the header and the columns by translating them at the right position whenever the scroll position is changed.

This technique works fine, when I scroll horizontally the sticky columns are properly displayed at the fixed position, but when I start scrolling vertically the sticky column cells overlap the header cells and hide them.

Here is what I am seeing when it happens

I tried to play with the z-index to make sure the header is always on top of the rows, but for some reason it's not working.

If anyone ever encountered this issue and could share a way to fix it, that would be really appreciated.

Thanks in advance.

HTML:

<table class="tablesorter">
    <thead class="sticky-header">
        <tr>
            <th class="sticky-column">Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            ...
        </tr>
    </thead>
    <tbody>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            ...
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            ...
        </tr>
    </tbody>
</table>

Javascript:

var $win = $(window),
$stickyHeader = $('.sticky-header'),
$stickyColumns = $('.sticky-column');

$(document).on('scroll', function () {
    deltaY = $win.scrollTop() - $stickyHeader.offset().top;
    deltaX = $win.scrollLeft() - $stickyHeader.offset().left;
    $stickyHeader.children().css({
        "transform": "translate(0px," + (deltaY > 0 ? deltaY : 0) + 
"px)"
    });
    $stickyColumns.css({
        "transform": "translate(" + (deltaX > 0 ? deltaX : 0) + "px, 
0px)"
    });
});

CSS:

    table {
    margin: 100px auto 800px auto;
}

thead th {
  background-color: yellow;
  border-right: 2px solid black;
  border-left: 2px solid black;
  border-bottom: 1px solid black;
  border-top: 1px solid black;
  height: 60px;
  z-index: 3;
}
tbody td {
  background-color: red;
  border-right: 2px solid black;
  border-left: 2px solid black;
  border-bottom: 1px solid black;
  border-top: 1px solid black;
  height: 30px;
  z-index: 1;
}

tbody td.sticky-column {
  z-index: 2;
}

tbody th.sticky-column {
  z-index: 4;
}

Here is the JSFiddle reproducing the issue: http://jsfiddle.net/asoua/5942rqty/

Upvotes: 2

Views: 10166

Answers (5)

Karlth
Karlth

Reputation: 3275

Set z-index:1 on the th cells.

Upvotes: 0

Paulo Belo
Paulo Belo

Reputation: 4437

This is a solution for a HTML table with sticky columns and rows headers, using only CSS. For more info you can check here.

/* set some spacing (optional)*/
td,
th {
  padding: 20px;
}

/* style columns table headings*/
th[scope=col] {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 1;
  background-color: teal;
}

/* style columns headings first element*/
th[scope=col]:nth-of-type(1) {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  left: 0;
  z-index: 2;
  background-color: peru;
}

/* style rows table headings*/
th[scope=row] {
  position: -webkit-sticky;
  position: sticky;
  left: 0;
  z-index: 1;
  background-color: chocolate;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Sales</title>
</head>

<body>
  <h1>ACME Company</h1>
  <table>
    <tr>
      <th scope="col">Sales by Country</th>
      <th scope="col">January</th>
      <th scope="col">February</th>
      <th scope="col">March</th>
      <th scope="col">April</th>
      <th scope="col">May</th>
      <th scope="col">June</th>
      <th scope="col">July</th>
      <th scope="col">August</th>
      <th scope="col">September</th>
      <th scope="col">October</th>
      <th scope="col">November</th>
      <th scope="col">December</th>
    </tr>
    <tr>
      <th scope="row">Portugal</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">Spain</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">France</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">Germany</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">Italy</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">Poland</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">Austria</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">United States</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">England</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">Scotland</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
    <tr>
      <th scope="row">Wales</th>
      <td>50.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
      <td>52.000</td>
    </tr>
  </table>

</body>

</html>

Upvotes: 0

tdjprog
tdjprog

Reputation: 719

try this sollution

.sticky-header {
    position: absolute;
    z-index: 4;
}

i suggest to use grid unstead of table

Upvotes: 1

Todd Chaffee
Todd Chaffee

Reputation: 6824

I used a combination of z-index, and a change to your logic to get it working. That corner column needs both and x and y axis transforms.

var $win = $(window),
    $stickyHeader = $('.sticky-header'),
    $stickyColumns = $('.sticky-column'),
    $stickyCorner = $('.sticky-corner');
    

$(document).on('scroll', function () {
    deltaY = $win.scrollTop() - $stickyHeader.offset().top;
    deltaX = $win.scrollLeft() - $stickyHeader.offset().left;

    $stickyColumns.css({
        "transform": "translate(" + (deltaX > 0 ? deltaX : 0) + "px, 0px)"
    });
    
    $stickyHeader.children().css({
        "transform": "translate(0px," + (deltaY > 0 ? deltaY : 0) + "px)"
    });
    
    $stickyCorner.css({
        "transform": "translate(" + (deltaX > 0 ? deltaX : 0) + "px," + (deltaY > 0 ? deltaY : 0) + "px)"
    });    


});
table {
    margin: 100px auto 800px auto;
}

thead th {
  background-color: yellow;
  border-right: 2px solid black;
  border-left: 2px solid black;
  border-bottom: 1px solid black;
  border-top: 1px solid black;
  height: 60px;
  z-index: 3;
}
tbody td {
  background-color: red;
  border-right: 2px solid black;
  border-left: 2px solid black;
  border-bottom: 1px solid black;
  border-top: 1px solid black;
  height: 30px;
  z-index: 1;
}

tbody td.sticky-column {
  z-index: 1;
}

thead tr.sticky-column {
  z-index: 2;
}

thead th.sticky-corner {
  background-color: orange;
  z-index: 10;
  position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="tablesorter">
    <thead>
        <tr class="sticky-header">
            <th class="sticky-corner">Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
            <th>Whatever Header</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
        <tr>
            <td class="sticky-column">Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
            <td>Whatever</td>
        </tr>
    </tbody>
</table>

Upvotes: 2

You can use the following attributes:

  position: -webkit-sticky; /* for Safari */
  position: sticky;

If you use this for example on the first child of a column, or a the full header, it will make your desire effect.

    <tbody>
        <tr>
            <th>Whatever</th>
            <td>Whatever</td>
            ...
        </tr>
        <tr>
            <th>Whatever</th>
            <td>Whatever</td>
            ...
        </tr>
    </tbody>


thead th {
  z-index:999;
  top:0;
  position: -webkit-sticky;
  position: sticky;
}

tbody th {
  left:0;
  position: -webkit-sticky;
  position: sticky;
}

tbody th:first-child {
  position: -webkit-sticky; 
  position: sticky;
  z-index: 999;
  left:0;
}

Try it!

Upvotes: 0

Related Questions