Reputation: 1802
Is there an effective way to use position: sticky with multiple th rows?
<table id="table-example" class="table mw-850">
<thead>
<tr>
<th></th>
<th colspan="2" class="text-center" scope="col">Checked In</th>
<th colspan="2" class="text-center" scope="col">Checked Out</th>
</tr>
<tr>
<th scope="col" style="background-color: #fdfdfe;">Action</th>
<th class="text-center" scope="col">Email</th>
<th class="text-center" scope="col">Event</th>
<th class="text-center" scope="col">Email</th>
<th class="text-center" scope="col">Event</th>
</tr>
</thead>
<tbody>
...
And CSS
.table thead th {
position: sticky !important;
top: -1px !important;
z-index: 1;
}
When I scroll, the collapse on top of each other.
Upvotes: 0
Views: 101
Reputation: 155045
Unfortunately, there's no built-in way in CSS that correctly handles "position: sticky, but relative to another sticky element", so when I needed to do this same thing earlier this month I used ResizeObserver
in a script to adjust the top:
offset of the second row.
Fortunately it's pretty straightforward to use:
window.addEventListener( 'DOMContentLoaded', setUpStickyHeaders );
function setUpStickyHeaders() {
if( typeof window.ResizeObserver !== 'function' ) return;
const headerFirstRow = document.querySelector( 'table > thead > tr:first-child' );
const headerSecondRowCells = document.querySelectorAll( 'table > thead > tr:not(:first-child) > th' );
function onHeaderFirstRowResize( entries, observer ) {
for( const entry of entries ) {
if( entry !== headerFirstRow ) continue;
const firstRowBottom = entry.contentRect.bottom;
for( const th of headerSecondRowCells ) {
th.style.top = firstRowBottom.toString() + 'px'; // I find I often have to add a few extra px here for it to look good though.
}
}
}
const ro = new ResizeObserver( onHeaderFirstRowResize );
ro.observe( headerFirstRow );
}
This is supported by all major browsers except IE11 (of course) and Safari (both macOS Safari and iOS Safari), which does not currently support ResizeObserver
but there's a good polyfill available that works flawlessly for me.
Upvotes: 1