I need a simple solution. I know it\'s similar to some other questions, like:
//If the table has tbody and thead, make them the relative container in which we can fix td and th as absolute
table tbody {
position: relative;
}
table thead {
position: relative;
}
//Make both the first header and first data cells (First column) absolute so that it sticks to the left
table td:first-of-type {
position: absolute;
}
table th:first-of-type {
position: absolute;
}
//Move Second column according to the width of column 1
table td:nth-of-type(2) {
padding-left: <Width of column 1>;
}
table th:nth-of-type(2) {
padding-left: <Width of column 1>;
}
FWIW, here is a table that is scrollable with the head and side fixed.
http://codepen.io/ajkochanowicz/pen/KHdih
If you're developing something more complicated and want multiple columns to be fixed/stuck to the left, you'll probably need something like this.
.wrapper {
overflow-x: scroll;
}
td {
min-width: 50px;
}
.fixed {
position: absolute;
background: #aaa;
}
<div class="content" style="width: 400px">
<div class="wrapper" style="margin-left: 100px">
<table>
<thead>
<tr>
<th class="fixed" style="left: 0px">aaa</th>
<th class="fixed" style="left: 50px">aaa2</th>
<th>a</th>
<th>b</th>
<th>c</th>
<th>d</th>
<th>e</th>
<th>f</th>
<th>a</th>
<th>b</th>
<th>c</th>
<th>d</th>
<th>e</th>
<th>f</th>
<th>a</th>
<th>b</th>
<th>c</th>
<th>d</th>
<th>e</th>
<th>f</th>
<th>a</th>
<th>b</th>
<th>c</th>
<th>d</th>
<th>e</th>
<th>f</th>
</tr>
</thead>
<tbody>
<tr>
<td class="fixed" style="left: 0px">aaa</td>
<td class="fixed" style="left: 50px">aaa2</td>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
<td>f</td>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
<td>f</td>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
<td>f</td>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
<td>f</td>
</tr>
<tr>
<td class="fixed" style="left: 0">bbb</td>
<td class="fixed" style="left: 50px">bbb2</td>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
<td>f</td>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
<td>f</td>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
<td>f</td>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
<td>f</td>
</tr>
</tbody>
</table>
</div>
</div>
Alternatively, style the tbody with a predetermined size (via height:20em
, for example) and use overflow-y:scroll;
Then, you can have a huge tbody, which will scroll independently of the rest of the page.
For most browsers released after 2017:
You can use the position: sticky
. See https://caniuse.com/#feat=css-sticky.
There is no need for a fixed width column.
Run the code snippet below to see how it works.
.tscroll {
width: 400px;
overflow-x: scroll;
margin-bottom: 10px;
border: solid black 1px;
}
.tscroll table td:first-child {
position: sticky;
left: 0;
background-color: #ffffd;
}
.tscroll td, .tscroll th {
border-bottom: dashed #888 1px;
}
<html>
<div class="tscroll">
<table>
<thead>
<tr>
<th></th>
<th colspan="5">Heading 1</th>
<th colspan="8">Heading 2</th>
<th colspan="4">Heading 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>9:00</td>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
<td>KKK</td>
<td>LLL</td>
<td>MMM</td>
<td>NNN</td>
<td>OOO</td>
<td>PPP</td>
<td>QQQ</td>
</tr>
<tr>
<td>10:00</td>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
<td>KKK</td>
<td>LLL</td>
<td>MMM</td>
<td>NNN</td>
<td>OOO</td>
<td>PPP</td>
<td>QQQ</td>
</tr>
<tr>
<td>11:00</td>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
<td>KKK</td>
<td>LLL</td>
<td>MMM</td>
<td>NNN</td>
<td>OOO</td>
<td>PPP</td>
<td>QQQ</td>
</tr>
<tr>
<td>12:00</td>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
<td>KKK</td>
<td>LLL</td>
<td>MMM</td>
<td>NNN</td>
<td>OOO</td>
<td>PPP</td>
<td>QQQ</td>
</tr>
<tr>
<td>13:00</td>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
<td>KKK</td>
<td>LLL</td>
<td>MMM</td>
<td>NNN</td>
<td>OOO</td>
<td>PPP</td>
<td>QQQ</td>
</tr>
<tr>
<td>14:00</td>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
<td>KKK</td>
<td>LLL</td>
<td>MMM</td>
<td>NNN</td>
<td>OOO</td>
<td>PPP</td>
<td>QQQ</td>
</tr>
<tr>
<td>15:00</td>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
<td>KKK</td>
<td>LLL</td>
<td>MMM</td>
<td>NNN</td>
<td>OOO</td>
<td>PPP</td>
<td>QQQ</td>
</tr>
<tr>
<td>16:00</td>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
<td>KKK</td>
<td>LLL</td>
<td>MMM</td>
<td>NNN</td>
<td>OOO</td>
<td>PPP</td>
<td>QQQ</td>
</tr>
<tr>
<td>17:00</td>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
<td>KKK</td>
<td>LLL</td>
<td>MMM</td>
<td>NNN</td>
<td>OOO</td>
<td>PPP</td>
<td>QQQ</td>
</tr>
</tbody>
</table>
</div>
I didn't check each and every answer for this question, but after analyzing most of them I found that design fails in case of multiline data in cells or head. I used Javascript to solve this. I hope someone finds this helpful.
https://codepen.io/kushagrarora/pen/zeYaoY
var freezeTables = document.getElementsByClassName("freeze-pane");
[].forEach.call(freezeTables, ftable => {
var wrapper = document.createElement("div");
wrapper.className = "freeze-pane-wrapper";
var scroll = document.createElement("div");
scroll.className = "freeze-pane-scroll";
wrapper.appendChild(scroll);
ftable.parentNode.replaceChild(wrapper, ftable);
scroll.appendChild(ftable);
var heads = ftable.querySelectorAll("th:first-child");
let maxWidth = 0;
[].forEach.call(heads, head => {
var w = window
.getComputedStyle(head)
.getPropertyValue("width")
.split("px")[0];
if (Number(w) > Number(maxWidth)) maxWidth = w;
});
ftable.parentElement.style.marginLeft = maxWidth + "px";
ftable.parentElement.style.width = "calc(100% - " + maxWidth + "px)";
[].forEach.call(heads, head => {
head.style.width = maxWidth + "px";
var restRowHeight = window
.getComputedStyle(head.nextElementSibling)
.getPropertyValue("height");
var headHeight = window.getComputedStyle(head).getPropertyValue("height");
if (headHeight > restRowHeight)
head.nextElementSibling.style.height = headHeight;
else head.style.height = restRowHeight;
});
});
@import url("https://fonts.googleapis.com/css?family=Open+Sans");
* {
font-family: "Open Sans", sans-serif;
}
.container {
width: 400px;
height: 90vh;
border: 1px solid black;
overflow: hidden;
}
table,
th,
td {
border: 1px solid #eee;
}
.table {
width: 100%;
margin-bottom: 1rem;
table-layout: fixed;
border-collapse: collapse;
}
.freeze-pane-wrapper {
position: relative;
}
.freeze-pane-scroll {
overflow-x: scroll;
overflow-y: visible;
}
.freeze-pane th:first-child {
position: absolute;
background-color: pink;
left: 0;
top: auto;
max-width: 40%;
}
<div class="container">
<table class="freeze-pane">
<tbody>
<tr>
<th>
<p>Model</p>
</th>
<th>
<p>Mercedes Benz AMG C43 4dr</p>
</th>
<th>
<p>Audi S4 Premium 4dr</p>
</th>
<th>
<p>BMW 440i 4dr sedan</p>
</th>
</tr>
<tr>
<th>
<p>Passenger capacity</p>
</th>
<td>
<p>5</p>
</td>
<td>
<p>5</p>
</td>
<td>
<p>5</p>
</td>
</tr>
<tr>
<th>
<p>Front (Head/Shoulder/Leg) (In.)</p>
</th>
<td>
<p>37.1/55.3/41.7</p>
</td>
<td>
<p>38.9/55.9/41.3</p>
</td>
<td>
<p>39.9/54.8/42.2</p>
</td>
</tr>
<tr>
<th>
<p>Second (Head/Shoulder/Leg) (In.)</p>
</th>
<td>
<p>37.1/55.5/35.2</p>
</td>
<td>
<p>37.4/54.5/35.7</p>
</td>
<td>
<p>36.9/54.3/33.7</p>
</td>
</tr>
</tbody>
</table>
</div>
Note: the "container" div is just to demonstrate that code is compatible with mobile-view.