Fixed Header Table With Horizontal Scrollbar and Vertical Scrollbar On

table with sticky header and horizontal scroll

As per the MDN documentation:

a sticky element "sticks" to its nearest ancestor that has a "scrolling mechanism" (created when overflow is hidden, scroll, auto, or overlay), even if that ancestor isn't the nearest actually scrolling ancestor.

There's an active GitHub issue discussing this on the W3C repo, which has been running since 2017. There have been various workarounds suggested, but they all seem to rely on adding a fixed height to the table / table container, or using Javascript as in this answer.

At least for the moment, this is not something that's supported natively.

Fixed table header with horizontal AND vertical scrolling body

You are cloning the table for fix header, better you can direct fix the header of original table which will results the same.

Element with position:fixed changes the width with respect to viewport, which results width gets change on scrolling as you can check here https://jsfiddle.net/chourasiapawankumar/vg7q3tyc/19

Approach:1

instead of position:fixed use relative in th and it is working with your parent div which has min-height:100px.

https://jsfiddle.net/chourasiapawankumar/krw0qpbL/62/

Approach:2

You can see both horizontal and vertical scroll bar at a time on removing min-height of parent div which I have commented in the below fiddle.

https://jsfiddle.net/chourasiapawankumar/vg7q3tyc/33/

Extra horizontal scroll bar on fixed-header HTML table?

The scrollbar you are talking about is being added to the tbody element. By turning tbody into a block, overscroll:auto is being added by default, even though you only include overflow-y in your CSS:

thead tr, tbody {
display: block;
}
tbody {
height: 300px;
overflow-y: auto;
}

Partial Solution (works when there is no horizontal overflow)

Adding overflow-y:hidden to tbody will remove the second horizontal scrollbar, and this works when there is no horizontal overflow. However if there is, the vertical scrollbar gets "stuck" to the column positioned at the max-width and scrolls with the tbody, as you can see here:

table {
table-layout: fixed;
width: 100%;
}

thead tr, tbody {
display: block;
}

tbody {
height: 300px;
overflow-y: auto;
overflow-x: hidden;
}

th, td {
width: 100px;
min-width: 100px;
}
<html>
<div style="max-width: 500px; overflow-y: auto;">
<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
<th>Column 5</th>
<th>Column 6</th>
<th>Column 7</th>
<th>Column 8</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
<tr>
<td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
<td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
</tr>
</tbody>
</table>
</div>
</html>

Mat Table with sticky header and Horizontal ,vertical scroll bar

You can set the width and height to the div container wrap around the mat-table. On stylesheet, you can apply something like this:

.example-container {
width: 100%;
height: calc(100vh - 32px);
overflow: auto;
}

Example: https://stackblitz.com/edit/angular-hdg9xh-uxkaeh

Table with horizontal and vertical scroll with fixed header

There's a simple CSS solution to fix rows(headers) and columns in a table.

th {
position: sticky:
top: 0;
}

The above snippet will fix the header to the top. Then it's just a matter of adding a simple overflow to the parent container of the table. You can find a simple example below -

.table-container {  overflow: auto;  max-height: 160px;  border: 1px solid red;}
th { position: sticky; top: 0; background: white;}
<div class="table-container">  <table>    <thead>      <tr>        <th>Head 1</th>        <th>Head 2</th>        <th>Head 3</th>        <th>Head 4</th>      </tr>    </thead>    <tbody>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>      <tr>        <td>Data</td>        <td>Data</td>        <td>Data</td>        <td>Data</td>      </tr>    </tbody>  </table></div>

Fixed table header scroll both horizontal and vertical CSS ONLY

This is another one of those interesting challenges (like vertical centering) brought to us by the inaction of the W3C. Also like vertical centering, you can't put a fixed header on a table with a horizontal scrollbar using position: fixed; on the thead element. But you do have a couple of options.

Option 1 - Horizontal Scrolling (http://codepen.io/staypuftman/pen/JXbpvZ)

The key here is to reestablish your table layout as table-layout: fixed; CSS-tricks has a good piece on this approach and then put a min-width value on your container when you want the scrollbars to appear. This makes the table scrollable left to right and maintains the integrity of the column headers on smaller devices. But the header is not fixed.

Option 2 - Fixed Header (https://jsfiddle.net/dPixie/byB9d/3/light/)

Your code looked like a rip-off of this guy's work, so I thought I'd repost here to give him some credit. This approach creates a series of <div> elements that mirror the contents of the <th> elements and uses some VERY creative positioning techniques to get it all to work.

There is a much better run-down on Salzar design that shows some examples and explains in detail all the complicated maneuvers to get this right.

Horizontal scrollbar on table with sticky header

i have fixed this issue by providing the container a fixed max height, that way it will have the sticky header and scrolling as well.

.table-flow {
max-height: 555px;
overflow-x: scroll;
max-width: auto;
position: relative;
}

Table header fixed, scrollable body horizontal and vertical, variable cell width

Edited to handle the possibility of longer columns, as I didn't notice that prerequisite

Interesting problem!

You can achieve what you want with less CSS and no jQuery, if you are happy to set a fixed width for the columns:

If you ensure that your CSS is set so that the default column width is as long as is necessary for any table headers, then this solution should work:

CSS

table#vehicleTable {
position: relative;
display: block;
margin-left: 0px;
width: 400px;
height: 400px;
overflow-x: scroll;
overflow-y: hidden;
}
table#vehicleTable thead {
background-color: blue;
color: white;
}
table#vehicleTable tbody {
position: relative;
display: inline-block;
height: 345px; /*allowing for scrollbar and th height */
overflow-y: scroll;
}
table#vehicleTable td, table#vehicleTable th {
min-width: 100px; /*suitable width for all column headers in the example*/
}

/*Added this just to handle the 2nd column, which needs to be smaller, as per comments */

table#vehicleTable td:nth-of-type(2), table#vehicleTable th:nth-of-type(2) {
min-width: 30px;
text-align: center;
}

jQuery

$(window).on('load', function () {
$i = 0;
$("#vehicleTable tbody tr:first-of-type td").each(function()
{
$i++;
width = $(this).outerWidth();
$("#vehicleTable thead th:nth-of-type(" +$i+")").css({"min-width": width+"px"});
});
});

This will loop through the first row of tbody, and get the respective widths for each column. If you don't set a min-width on them first, then any columns with data that is shorter than the column header will result in that column shrinking, while the header itself will still expand to fit its own content.

Also updated JSFiddle



Related Topics



Leave a reply



Submit