table header sticky test

table header sticky test

by Laurens Maneschijn

HTML

<code>position: sticky;</code> is far from bug free, but it helps for very basic tables.<br>
<br>
<br>
Slowly scroll down to see the table headers move.<br>
(and for the last table scroll left/right)<br>

<hr class="margin_v_xl">

Table with both sticky top and footer headers:<br>
<table border=1>
	<thead>
		<tr>
			<th>th1</th>
			<th>th2</th>
			<th>th3</th>
		</tr>
	</thead>
	<tbody>
		<tr><td>1</td><td>2</td><td>3</td></tr>
		<tr><td>1</td><td>2</td><td>3</td></tr>
		<tr><td>1</td><td>2</td><td>3</td></tr>
	</tbody>
	<thead>
		<tr>
			<th>th1</th>
			<th>th2</th>
			<th>th3</th>
		</tr>
	</thead>
</table>

<hr>

Table with both sticky top and footer (thead and tfoot):<br>
<table border=1>
	<thead>
		<tr>
			<th>th1</th>
			<th>th2</th>
			<th>th3</th>
		</tr>
	</thead>
	<tbody>
		<tr><td>1</td><td>2</td><td>3</td></tr>
		<tr><td>1</td><td>2</td><td>3</td></tr>
		<tr><td>1</td><td>2</td><td>3</td></tr>
	</tbody>
	<tfoot>
		<tr>
			<th>th1</th>
			<th>th2</th>
			<th>th3</th>
		</tr>
	</tfoot>
</table>

<hr>

Table with 3 <tr> rows of header cells, with some rowspan and colspan in the mix:<br>
<table border=1>
	<thead>
		<tr>
			<th>r1 th1</th>
			<th rowspan="2">r1 th2 rowspan=2</th>
			<th colspan="2">r1 th3 colspan=2</th>
		</tr>
		<tr>
			<th>r2 th1</th>
			<th>r2 th2</th>
			<th rowspan="2">r2 th2</th>
		</tr>
		<tr>
			<th>r3 th1</th>
			<th>r3 th2</th>
			<th>r3 th2</th>
		</tr>
	</thead>
	<tbody>
		<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
		<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
		<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
	</tbody>
</table>

<hr>

Table with sticky header columns on the left (1,2) and right (5,6) side:<br>
<table border=1...

CSS

table thead tr th,
table tfoot tr th {
	position: sticky;
	position: --webkit-sticky;
	top: 0;
}
/* Assume thet final child in <table> 
   is the footer <thead> and align to bottom (if exists):
*/
table thead:last-child tr th,
table tfoot tr th {
	bottom: 0;
}
/* if a <thead> has 2 rows, put the 2nd row a bit more down:
   Note that the 1.5em is a hardcoded value that seems to about match for default borders,
	 but it does not take into account the real size of the 1st row in any way.
	 Also you need to repeat this for each additional <tr>.
*/
table thead tr:nth-child(2) th,
table tfoot tr:nth-child(2) th {
	top: 1.5em;
}
table thead tr:nth-child(3) th,
table tfoot tr:nth-child(3) th {
	top: 3em;
}

table tbody tr th {
	position: sticky;
	position: --webkit-sticky;
}

table tbody tr th:first-child {
	left: 0;
}
/* Note it is fairly impossible to guess a good hardcoded left value,
   especially if first column width is unknown or dynamic.
*/
table tbody tr th:nth-child(2) {
	left: 200px;
}
table tbody tr th:last-child {
	right: 0;
}
/* Note it is fairly impossible to guess a good hardcoded right value,
   especially if last column width is unknown or dynamic.
*/
table tbody tr th:nth-last-child(2) {
	right: 200px;
}

/* make table cells a big bigger,
   to more easily create larger tables with just little html code: */
table tbody th ,
table tbody td {
	width: 100px;
	height: 100px;
}

table th {
	background-color: rgba(128, 128, 128, 0.5);
}


/* large vertical margin so we have plenty of room to scroll up/down and see the headers move:
*/
.margin_v_xl {
	margin: 200px 0;
}
.margin_top_xl {
	margin-top: 200px;
}
.margin_bottom_xl {
	margin-top: 200px;
}