Css-Only Scrollable Table With Fixed Headers

CSS-Only Scrollable Table with fixed headers

This answer will be used as a placeholder for the not fully supported position: sticky and will be updated over time. It is currently advised to not use the native implementation of this in a production environment.

See this for the current support: https://caniuse.com/#feat=css-sticky


Use of position: sticky

An alternative answer would be using position: sticky. As described by W3C:

A stickily positioned box is positioned similarly to a relatively positioned box, but the offset is computed with reference to the nearest ancestor with a scrolling box, or the viewport if no ancestor has a scrolling box.

This described exactly the behavior of a relative static header. It would be easy to assign this to the <thead> or the first <tr> HTML-tag, as this should be supported according to W3C. However, both Chrome, IE and Edge have problems assigning a sticky position property to these tags. There also seems to be no priority in solving this at the moment.

What does seem to work for a table element is assigning the sticky property to a table-cell. In this case the <th> cells.

Because a table is not a block-element that respects the static size you assign to it, it is best to use a wrapper element to define the scroll-overflow.

The code

div {  display: inline-block;  height: 150px;  overflow: auto}
table th { position: -webkit-sticky; position: sticky; top: 0;}

/* == Just general styling, not relevant :) == */
table { border-collapse: collapse;}
th { background-color: #1976D2; color: #fff;}
th,td { padding: 1em .5em;}
table tr { color: #212121;}
table tr:nth-child(odd) { background-color: #BBDEFB;}
<div>  <table border="0">    <thead>      <tr>        <th>head1</th>        <th>head2</th>        <th>head3</th>        <th>head4</th>      </tr>    </thead>    <tr>      <td>row 1, cell 1</td>      <td>row 1, cell 2</td>      <td>row 1, cell 2</td>      <td>row 1, cell 2</td>    </tr>    <tr>      <td>row 2, cell 1</td>      <td>row 2, cell 2</td>      <td>row 1, cell 2</td>      <td>row 1, cell 2</td>    </tr>    <tr>      <td>row 2, cell 1</td>      <td>row 2, cell 2</td>      <td>row 1, cell 2</td>      <td>row 1, cell 2</td>    </tr>    <tr>      <td>row 2, cell 1</td>      <td>row 2, cell 2</td>      <td>row 1, cell 2</td>      <td>row 1, cell 2</td>    </tr>    <tr>      <td>row 2, cell 1</td>      <td>row 2, cell 2</td>      <td>row 1, cell 2</td>      <td>row 1, cell 2</td>    </tr>  </table></div>

Table fixed header and scrollable body

Here is the working solution:

table {    width: 100%;}
thead, tbody, tr, td, th { display: block; }
tr:after { content: ' '; display: block; visibility: hidden; clear: both;}
thead th { height: 30px;
/*text-align: left;*/}
tbody { height: 120px; overflow-y: auto;}
thead { /* fallback */}

tbody td, thead th { width: 19.2%; float: left;}
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"/>
<table class="table table-striped"> <thead> <tr> <th>Make</th> <th>Model</th> <th>Color</th> <th>Year</th> </tr> </thead> <tbody> <tr> <td class="filterable-cell">Ford</td> <td class="filterable-cell">Escort</td> <td class="filterable-cell">Blue</td> <td class="filterable-cell">2000</td> </tr> <tr> <td class="filterable-cell">Ford</td> <td class="filterable-cell">Escort</td> <td class="filterable-cell">Blue</td> <td class="filterable-cell">2000</td> </tr> <tr> <td class="filterable-cell">Ford</td> <td class="filterable-cell">Escort</td> <td class="filterable-cell">Blue</td> <td class="filterable-cell">2000</td> </tr> <tr> <td class="filterable-cell">Ford</td> <td class="filterable-cell">Escort</td> <td class="filterable-cell">Blue</td> <td class="filterable-cell">2000</td> </tr> </tbody></table>

table with fixed thead and scrollable tbody

This solution fulfills all 5 requirements:

table {  width: 100%;}
table, td { border-collapse: collapse; border: 1px solid #000;}
thead { display: table; /* to take the same width as tr */ width: calc(100% - 17px); /* - 17px because of the scrollbar width */}
tbody { display: block; /* to enable vertical scrolling */ max-height: 200px; /* e.g. */ overflow-y: scroll; /* keeps the scrollbar even if it doesn't need it; display purpose */}
th, td { width: 33.33%; /* to enable "word-break: break-all" */ padding: 5px; word-break: break-all; /* 4. */}
tr { display: table; /* display purpose; th's border */ width: 100%; box-sizing: border-box; /* because of the border (Chrome needs this line, but not FF) */}
td { text-align: center; border-bottom: none; border-left: none;}
<table>   <thead>     <tr>      <th>Table Header 1</th>      <th>Table Header 2</th>      <th>Table Header 3</th>    </tr>   </thead>  <tbody>    <tr>      <td>Data1111111111111111111111111</td>      <td>Data</td>      <td>Data</td>    </tr>    <tr>      <td>Data</td>      <td>Data2222222222222222222222222</td>      <td>Data</td>    </tr>    <tr>      <td>Data</td>      <td>Data</td>      <td>Data3333333333333333333333333</td>    </tr>    <tr>      <td>Data</td>      <td>Data</td>      <td>Data</td>    </tr>    <tr>      <td>Data</td>      <td>Data</td>      <td>Data</td>    </tr>    <tr>      <td>Data</td>      <td>Data</td>      <td>Data</td>    </tr>    <tr>      <td>Data</td>      <td>Data</td>      <td>Data</td>    </tr>    <tr>      <td>Data</td>      <td>Data</td>      <td>Data</td>    </tr>    <tr>      <td>Data</td>      <td>Data</td>      <td>Data</td>    </tr>    <tr>      <td>Data</td>      <td>Data</td>      <td>Data</td>    </tr>  </tbody></table>

Create scroll bar for HTML 5 Table With Fixed Header

This will solve ur problem

.table-responsive{  height:400px;    overflow:scroll;} thead tr:nth-child(1) th{    background: white;    position: sticky;    top: 0;    z-index: 10;  }
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div class="table-responsive"> <table class="table table-hover" id="job-table"> <thead> <tr class="text-center"> <th scope="col">Applicant ▼</th> <th scope="col">State</th> <th scope="col">EIN</th> <th scope="col">DUNS</th> <th scope="col">Grant Type</th> <th scope="col">Status</th> </tr> </thead> <tbody class="text-center tableBody"> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> <tr> <td>City of Charlottesville Public Schools</td> <td>Virginia</td> <td>33-1234888</td> <td>88-111-8235</td> <td>Discretionary</td> <td>Active</td> </tr> </tbody> </table> </div>

Freeze the top row for an html table only (Fixed Table Header Scrolling)

This is called Fixed Header Scrolling. There are a number of documented approaches:

http://www.imaputz.com/cssStuff/bigFourVersion.html

You won't effectively pull this off without JavaScript ... especially if you want cross browser support.

There are a number of gotchyas with any approach you take, especially concerning cross browser/version support.

Edit:

Even if it's not the header you want to fix, but the first row of data, the concept is still the same. I wasn't 100% which you were referring to.

Additional thought
I was tasked by my company to research a solution for this that could function in IE7+, Firefox, and Chrome.

After many moons of searching, trying, and frustration it really boiled down to a fundamental problem. For the most part, in order to gain the fixed header, you need to implement fixed height/width columns because most solutions involve using two separate tables, one for the header which will float and stay in place over the second table that contains the data.

//float this one right over second table
<table>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
</table>

<table>
//Data
</table>

An alternative approach some try is utilize the tbody and thead tags but that is flawed too because IE will not allow you put a scrollbar on the tbody which means you can't limit its height (so stupid IMO).

<table>
<thead style="do some stuff to fix its position">
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
</thead>
<tbody style="No scrolling allowed here!">
Data here
</tbody>
</table>

This approach has many issues such as ensures EXACT pixel widths because tables are so cute in that different browsers will allocate pixels differently based on calculations and you simply CANNOT (AFAIK) guarantee that the distribution will be perfect in all cases. It becomes glaringly obvious if you have borders within your table.

I took a different approach and said screw tables since you can't make this guarantee. I used divs to mimic tables. This also has issues of positioning the rows and columns (mainly because floating has issues, using in-line block won't work for IE7, so it really left me with using absolute positioning to put them in their proper places).

There is someone out there that made the Slick Grid which has a very similar approach to mine and you can use and a good (albeit complex) example for achieving this.

https://github.com/6pac/SlickGrid/wiki

How do I create an HTML table with a fixed/frozen left column and a scrollable body?

If you want a table where only the columns scroll horizontally, you can position: absolute the first column (and specify its width explicitly), and then wrap the entire table in an overflow-x: scroll block. Don't bother trying this in IE7, however...

Relevant HTML & CSS:

table {
border-collapse: separate;
border-spacing: 0;
border-top: 1px solid grey;
}

td,
th {
margin: 0;
border: 1px solid grey;
white-space: nowrap;
border-top-width: 0px;
}

div {
width: 500px;
overflow-x: scroll;
margin-left: 5em;
overflow-y: visible;
padding: 0;
}

.headcol {
position: absolute;
width: 5em;
left: 0;
top: auto;
border-top-width: 1px;
/*only relevant for first row*/
margin-top: -1px;
/*compensate for top border*/
}

.headcol:before {
content: 'Row ';
}

.long {
background: yellow;
letter-spacing: 1em;
}
<div>
<table>
<tr>
<th class="headcol">1</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">2</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">3</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">4</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">5</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">6</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
</table>
</div>


Related Topics



Leave a reply



Submit