I am trying to make a table with fixed header and a scrollable content using the bootstrap 3 table. Unfortunately the solutions I have found does not work with bootstrap or
By far the best solution I've seen that is CSS only, with good cross browser support, and no alignment issues is this solution from codingrabbithole
table {
width: 100%;
}
thead, tbody tr {
display: table;
width: 100%;
table-layout: fixed;
}
tbody {
display: block;
overflow-y: auto;
table-layout: fixed;
max-height: 200px;
}
An easy way without fixed width:
.myTable tbody{
display:block;
overflow:auto;
height:200px;
width:100%;
}
.myTable thead tr{
display:block;
}
Source
Now, on onLoad, to adjust th widths, just add this jquery script:
$.each($('.myTable tbody tr:nth(0) td'), function(k,v) {
$('.myTable thead th:nth('+k+')').css('width', $(v).css('width'));
});
Now that “all” browsers support ES6, I’ve incorporated the various suggestions above into a JavaScript class that takes a table as an argument and makes the body scrollable. It lets the browser’s layout engine determine header and body cell widths, and then makes the column widths match each other.
The height of a table can be set explicitly, or made to fill the remaining part of the browser window, and provides callbacks for events such as viewport resizing and/or details
elements opening or closing.
Multi-row header support is available, and is especially effective if the table uses the id/headers attributes for accessibility as specified in the WCAC Guidelines, which is not as onerous a requirement as it might seem.
The code does not depend on any libraries, but plays nicely with them if they are being used. (Tested on pages that use JQuery).
The code and sample usage are available on Github.
Simply position: sticky; top: 0;
your th
elements. (Chrome, FF, Edge)
.tableFixHead { overflow-y: auto; height: 100px; }
.tableFixHead thead th { position: sticky; top: 0; }
/* Just common table stuff. Really. */
table { border-collapse: collapse; width: 100%; }
th, td { padding: 8px 16px; }
th { background:#eee; }
<div class="tableFixHead">
<table>
<thead>
<tr><th>TH 1</th><th>TH 2</th></tr>
</thead>
<tbody>
<tr><td>A1</td><td>A2</td></tr>
<tr><td>B1</td><td>B2</td></tr>
<tr><td>C1</td><td>C2</td></tr>
<tr><td>D1</td><td>D2</td></tr>
<tr><td>E1</td><td>E2</td></tr>
</tbody>
</table>
</div>
Since border
cannot be painted properly on a translated TH
element,
to recreate and render "borders" use the box-shadow
property:
/* Borders (if you need them) */
.tableFixHead,
.tableFixHead td {
box-shadow: inset 1px -1px #000;
}
.tableFixHead th {
box-shadow: inset 1px 1px #000, 0 1px #000;
}
.tableFixHead { overflow-y: auto; height: 100px; }
.tableFixHead thead th { position: sticky; top: 0; }
/* Just common table stuff. Really. */
table { border-collapse: collapse; width: 100%; }
th, td { padding: 8px 16px; }
th { background:#eee; }
/* Borders (if you need them) */
.tableFixHead,
.tableFixHead td {
box-shadow: inset 1px -1px #000;
}
.tableFixHead th {
box-shadow: inset 1px 1px #000, 0 1px #000;
}
<div class="tableFixHead">
<table>
<thead>
<tr><th>TH 1</th><th>TH 2</th></tr>
</thead>
<tbody>
<tr><td>A1</td><td>A2</td></tr>
<tr><td>B1</td><td>B2</td></tr>
<tr><td>C1</td><td>C2</td></tr>
<tr><td>D1</td><td>D2</td></tr>
<tr><td>E1</td><td>E2</td></tr>
</tbody>
</table>
</div>
You can use a bit of JS and translateY the th
elements
jQuery example
var $th = $('.tableFixHead').find('thead th')
$('.tableFixHead').on('scroll', function() {
$th.css('transform', 'translateY('+ this.scrollTop +'px)');
});
.tableFixHead { overflow-y: auto; height: 100px; }
/* Just common table stuff. */
table { border-collapse: collapse; width: 100%; }
th, td { padding: 8px 16px; }
th { background:#eee; }
<div class="tableFixHead">
<table>
<thead>
<tr><th>TH 1</th><th>TH 2</th></tr>
</thead>
<tbody>
<tr><td>A1</td><td>A2</td></tr>
<tr><td>B1</td><td>B2</td></tr>
<tr><td>C1</td><td>C2</td></tr>
<tr><td>D1</td><td>D2</td></tr>
<tr><td>E1</td><td>E2</td></tr>
</tbody>
</table>
</div>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
Or plain ES6 if you prefer (no jQuery required):
// Fix table head
function tableFixHead (e) {
const el = e.target,
sT = el.scrollTop;
el.querySelectorAll("thead th").forEach(th =>
th.style.transform = `translateY(${sT}px)`
);
}
document.querySelectorAll(".tableFixHead").forEach(el =>
el.addEventListener("scroll", tableFixHead)
);
For tables that are full height (the page scrolls, not the table)
Note: I move the whole <thead>...</thead>
beause In my case I had two rows (Title and filters)
With JS (jQuery)
$( function() {
let marginTop = 0; // Add margin if the page has a top nav-bar
let $thead = $('.table-fixed-head').find('thead');
let offset = $thead.first().offset().top - marginTop;
let lastPos = 0;
$(window).on('scroll', function () {
if ( window.scrollY > offset )
{
if ( lastPos === 0 )
{
// Add a class for styling
$thead.addClass('floating-header');
}
lastPos = window.scrollY - offset;
$thead.css('transform', 'translateY(' + ( lastPos ) + 'px)');
}
else if ( lastPos !== 0 )
{
lastPos = 0;
$thead.removeClass('floating-header');
$thead.css('transform', 'translateY(' + 0 + 'px)');
}
});
});
CSS (Just for styling)
thead.floating-header>tr>th {
background-color: #efefef;
}
thead.floating-header>tr:last-child>th {
border-bottom: 1px solid #aaa;
}
Cleaner Solution (CSS Only)
.table-fixed tbody {
display:block;
height:85vh;
overflow:auto;
}
.table-fixed thead, .table-fixed tbody tr {
display:table;
width:100%;
}
<table class="table table-striped table-fixed">
<thead>
<tr align="center">
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Content 1</td>
<td>Content 1</td>
<td>Content 1</td>
<td>Content 1</td>
</tr>
<tr>
<td>Longer Content 1</td>
<td>Longer Content 1</td>
<td>Longer Content 1</td>
<td>Longer Content 1</td>
</tr>
</tbody
</table