I need a simple solution. I know it's similar to some other questions, like:
But I need just a single left column to be frozen and I would prefer a simple and script-less solution.
This question is related to
html
css
html-table
Eamon Nerbonne, I changed some css in your code and it's better now(the scroll bar starts from the first row)
I just add two line :
.div : padding-left:5em;
.headcol : background-color : #fff;
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.
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 {_x000D_
overflow-x: scroll;_x000D_
}_x000D_
_x000D_
td {_x000D_
min-width: 50px;_x000D_
}_x000D_
_x000D_
.fixed {_x000D_
position: absolute;_x000D_
background: #aaa;_x000D_
}
_x000D_
<div class="content" style="width: 400px">_x000D_
_x000D_
<div class="wrapper" style="margin-left: 100px">_x000D_
_x000D_
<table>_x000D_
<thead>_x000D_
<tr>_x000D_
<th class="fixed" style="left: 0px">aaa</th>_x000D_
<th class="fixed" style="left: 50px">aaa2</th>_x000D_
<th>a</th>_x000D_
<th>b</th>_x000D_
<th>c</th>_x000D_
<th>d</th>_x000D_
<th>e</th>_x000D_
<th>f</th>_x000D_
<th>a</th>_x000D_
<th>b</th>_x000D_
<th>c</th>_x000D_
<th>d</th>_x000D_
<th>e</th>_x000D_
<th>f</th>_x000D_
<th>a</th>_x000D_
<th>b</th>_x000D_
<th>c</th>_x000D_
<th>d</th>_x000D_
<th>e</th>_x000D_
<th>f</th>_x000D_
<th>a</th>_x000D_
<th>b</th>_x000D_
<th>c</th>_x000D_
<th>d</th>_x000D_
<th>e</th>_x000D_
<th>f</th> _x000D_
</tr>_x000D_
</thead>_x000D_
<tbody>_x000D_
<tr>_x000D_
<td class="fixed" style="left: 0px">aaa</td>_x000D_
<td class="fixed" style="left: 50px">aaa2</td>_x000D_
<td>a</td>_x000D_
<td>b</td>_x000D_
<td>c</td>_x000D_
<td>d</td>_x000D_
<td>e</td>_x000D_
<td>f</td>_x000D_
<td>a</td>_x000D_
<td>b</td>_x000D_
<td>c</td>_x000D_
<td>d</td>_x000D_
<td>e</td>_x000D_
<td>f</td>_x000D_
<td>a</td>_x000D_
<td>b</td>_x000D_
<td>c</td>_x000D_
<td>d</td>_x000D_
<td>e</td>_x000D_
<td>f</td>_x000D_
<td>a</td>_x000D_
<td>b</td>_x000D_
<td>c</td>_x000D_
<td>d</td>_x000D_
<td>e</td>_x000D_
<td>f</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td class="fixed" style="left: 0">bbb</td>_x000D_
<td class="fixed" style="left: 50px">bbb2</td>_x000D_
<td>a</td>_x000D_
<td>b</td>_x000D_
<td>c</td>_x000D_
<td>d</td>_x000D_
<td>e</td>_x000D_
<td>f</td>_x000D_
<td>a</td>_x000D_
<td>b</td>_x000D_
<td>c</td>_x000D_
<td>d</td>_x000D_
<td>e</td>_x000D_
<td>f</td>_x000D_
<td>a</td>_x000D_
<td>b</td>_x000D_
<td>c</td>_x000D_
<td>d</td>_x000D_
<td>e</td>_x000D_
<td>f</td>_x000D_
<td>a</td>_x000D_
<td>b</td>_x000D_
<td>c</td>_x000D_
<td>d</td>_x000D_
<td>e</td>_x000D_
<td>f</td>_x000D_
</tr>_x000D_
</tbody>_x000D_
</table>_x000D_
_x000D_
</div>_x000D_
_x000D_
</div>
_x000D_
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");_x000D_
_x000D_
[].forEach.call(freezeTables, ftable => {_x000D_
var wrapper = document.createElement("div");_x000D_
wrapper.className = "freeze-pane-wrapper";_x000D_
var scroll = document.createElement("div");_x000D_
scroll.className = "freeze-pane-scroll";_x000D_
_x000D_
wrapper.appendChild(scroll);_x000D_
_x000D_
ftable.parentNode.replaceChild(wrapper, ftable);_x000D_
_x000D_
scroll.appendChild(ftable);_x000D_
_x000D_
var heads = ftable.querySelectorAll("th:first-child");_x000D_
_x000D_
let maxWidth = 0;_x000D_
_x000D_
[].forEach.call(heads, head => {_x000D_
var w = window_x000D_
.getComputedStyle(head)_x000D_
.getPropertyValue("width")_x000D_
.split("px")[0];_x000D_
if (Number(w) > Number(maxWidth)) maxWidth = w;_x000D_
});_x000D_
_x000D_
ftable.parentElement.style.marginLeft = maxWidth + "px";_x000D_
ftable.parentElement.style.width = "calc(100% - " + maxWidth + "px)";_x000D_
[].forEach.call(heads, head => {_x000D_
head.style.width = maxWidth + "px";_x000D_
var restRowHeight = window_x000D_
.getComputedStyle(head.nextElementSibling)_x000D_
.getPropertyValue("height");_x000D_
var headHeight = window.getComputedStyle(head).getPropertyValue("height");_x000D_
if (headHeight > restRowHeight)_x000D_
head.nextElementSibling.style.height = headHeight;_x000D_
else head.style.height = restRowHeight;_x000D_
});_x000D_
});
_x000D_
@import url("https://fonts.googleapis.com/css?family=Open+Sans");_x000D_
* {_x000D_
font-family: "Open Sans", sans-serif;_x000D_
}_x000D_
_x000D_
.container {_x000D_
width: 400px;_x000D_
height: 90vh;_x000D_
border: 1px solid black;_x000D_
overflow: hidden;_x000D_
}_x000D_
_x000D_
table,_x000D_
th,_x000D_
td {_x000D_
border: 1px solid #eee;_x000D_
}_x000D_
_x000D_
.table {_x000D_
width: 100%;_x000D_
margin-bottom: 1rem;_x000D_
table-layout: fixed;_x000D_
border-collapse: collapse;_x000D_
}_x000D_
_x000D_
.freeze-pane-wrapper {_x000D_
position: relative;_x000D_
}_x000D_
_x000D_
.freeze-pane-scroll {_x000D_
overflow-x: scroll;_x000D_
overflow-y: visible;_x000D_
}_x000D_
_x000D_
.freeze-pane th:first-child {_x000D_
position: absolute;_x000D_
background-color: pink;_x000D_
left: 0;_x000D_
top: auto;_x000D_
max-width: 40%;_x000D_
}
_x000D_
<div class="container">_x000D_
<table class="freeze-pane">_x000D_
<tbody>_x000D_
<tr>_x000D_
<th>_x000D_
<p>Model</p>_x000D_
</th>_x000D_
<th>_x000D_
<p>Mercedes Benz AMG C43 4dr</p>_x000D_
</th>_x000D_
<th>_x000D_
<p>Audi S4 Premium 4dr</p>_x000D_
</th>_x000D_
<th>_x000D_
<p>BMW 440i 4dr sedan</p>_x000D_
</th>_x000D_
</tr>_x000D_
<tr>_x000D_
<th>_x000D_
<p>Passenger capacity</p>_x000D_
</th>_x000D_
<td>_x000D_
<p>5</p>_x000D_
</td>_x000D_
<td>_x000D_
<p>5</p>_x000D_
</td>_x000D_
<td>_x000D_
<p>5</p>_x000D_
</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<th>_x000D_
<p>Front (Head/Shoulder/Leg) (In.)</p>_x000D_
</th>_x000D_
<td>_x000D_
<p>37.1/55.3/41.7</p>_x000D_
</td>_x000D_
<td>_x000D_
<p>38.9/55.9/41.3</p>_x000D_
</td>_x000D_
<td>_x000D_
<p>39.9/54.8/42.2</p>_x000D_
</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<th>_x000D_
<p>Second (Head/Shoulder/Leg) (In.)</p>_x000D_
</th>_x000D_
<td>_x000D_
<p>37.1/55.5/35.2</p>_x000D_
</td>_x000D_
<td>_x000D_
<p>37.4/54.5/35.7</p>_x000D_
</td>_x000D_
<td>_x000D_
<p>36.9/54.3/33.7</p>_x000D_
</td>_x000D_
</tr>_x000D_
</tbody>_x000D_
</table>_x000D_
</div>
_x000D_
Note: the "container" div is just to demonstrate that code is compatible with mobile-view.
I just made the right-most sticky column of a table sticky.
th:last-of-type {
position: sticky;
right: 0;
width: 120px;
background: #f7f7f7;
}
td:last-of-type {
position: sticky;
right: 0;
background: #f7f7f7;
width: 120px;
}
I believe if you'll do {position: sticky; left: 0;}
, you'll get the desired result.
A little late but I did run across this thread when trying out solutions for myself. Assuming you're using modern browsers nowadays, I came up with a solution using CSS calc() to help guarantee widths met up.
.table-fixed-left table,_x000D_
.table-fixed-right table {_x000D_
border-collapse: collapse;_x000D_
}_x000D_
.table-fixed-right td,_x000D_
.table-fixed-right th,_x000D_
.table-fixed-left td,_x000D_
.table-fixed-left th {_x000D_
border: 1px solid #ddd;_x000D_
padding: 5px 5px;_x000D_
}_x000D_
.table-fixed-left {_x000D_
width: 120px;_x000D_
float: left;_x000D_
position: fixed;_x000D_
overflow-x: scroll;_x000D_
white-space: nowrap;_x000D_
text-align: left;_x000D_
border: 1px solid #ddd;_x000D_
z-index: 2;_x000D_
}_x000D_
.table-fixed-right {_x000D_
width: calc(100% - 145px);_x000D_
right: 15px;_x000D_
position: fixed;_x000D_
overflow-x: scroll;_x000D_
border: 1px solid #ddd;_x000D_
white-space: nowrap;_x000D_
}_x000D_
.table-fixed-right td,_x000D_
.table-fixed-right th {_x000D_
padding: 5px 10px;_x000D_
}
_x000D_
<div class="table-fixed-left">_x000D_
<table>_x000D_
<tr>_x000D_
<th>Normal Header</th>_x000D_
</tr>_x000D_
<tr>_x000D_
<th>Header with extra line_x000D_
<br/> </th>_x000D_
</tr>_x000D_
<tr>_x000D_
<th>Normal Header</th>_x000D_
</tr>_x000D_
<tr>_x000D_
<th>Normal with extra line_x000D_
<br/> </th>_x000D_
</tr>_x000D_
<tr>_x000D_
<th>Normal Header</th>_x000D_
</tr>_x000D_
<tr>_x000D_
<th>Normal Header</th>_x000D_
</tr>_x000D_
</table>_x000D_
</div>_x000D_
<div class="table-fixed-right">_x000D_
<table>_x000D_
<tr>_x000D_
<th>Header</th>_x000D_
<th>Another header</th>_x000D_
<th>Header</th>_x000D_
<th>Header really really really really long</th>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Info Long</td>_x000D_
<td>Info_x000D_
<br/>with second line</td>_x000D_
<td>Info_x000D_
<br/>with second line</td>_x000D_
<td>Info Long</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Info Long</td>_x000D_
<td>Info Long</td>_x000D_
<td>Info Long</td>_x000D_
<td>Info Long</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Info_x000D_
<br/>with second line</td>_x000D_
<td>Info_x000D_
<br/>with second line</td>_x000D_
<td>Info_x000D_
<br/>with second line</td>_x000D_
<td>Info</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Info</td>_x000D_
<td>Info</td>_x000D_
<td>Info</td>_x000D_
<td>Info</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Info</td>_x000D_
<td>Info</td>_x000D_
<td>Info</td>_x000D_
<td>Info</td>_x000D_
</tr>_x000D_
</table>_x000D_
</div>
_x000D_
Hope this helps someone!
If you don't want to touch your current table too much you can make a fake pinned column in front of the table.
The example shows one way of doing it without JS
table {_x000D_
border-collapse: collapse;_x000D_
border-spacing: 0;_x000D_
border: 1px solid #ddd;_x000D_
min-width: 600px;_x000D_
}_x000D_
_x000D_
.labels {_x000D_
display:flex;_x000D_
flex-direction: column_x000D_
}_x000D_
_x000D_
.overflow {_x000D_
overflow-x: scroll;_x000D_
min width: 400px;_x000D_
flex: 1;_x000D_
}_x000D_
_x000D_
.label {_x000D_
display: flex;_x000D_
align-items: center;_x000D_
white-space:nowrap;_x000D_
padding: 10px;_x000D_
flex: 1;_x000D_
border-bottom: 1px solid #ddd;_x000D_
border-right: 2px solid #ddd;_x000D_
}_x000D_
_x000D_
.label:last-of-type {_x000D_
overflow-x: scroll;_x000D_
border-bottom: 0;_x000D_
}_x000D_
_x000D_
td {_x000D_
border: 1px solid #ddd;_x000D_
padding: 10px;_x000D_
}_x000D_
_x000D_
.flex {_x000D_
display:flex;_x000D_
max-width: 600px;_x000D_
padding: 0;_x000D_
border: 5px solid #ddd;_x000D_
}
_x000D_
<div class="flex">_x000D_
<div class="labels">_x000D_
<span class="label">Label 1</span>_x000D_
<span class="label">Lorem ipsum dolor sit amet.</span>_x000D_
<span class="label">Lorem ipsum dolor.</span>_x000D_
</div>_x000D_
<div class="overflow">_x000D_
<table>_x000D_
<tr>_x000D_
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>_x000D_
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>_x000D_
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>_x000D_
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>_x000D_
</tr>_x000D_
</table>_x000D_
</div>_x000D_
</div>
_x000D_
In case of fixed width left column the best solution is provided by Eamon Nerbonne.
In case of variable width left column the best solution I found is to make two identical tables and push one above another. Demo: http://jsfiddle.net/xG5QH/6/.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
/* important styles */
.container {
/* Attach fixed-th-table to this container,
in order to layout fixed-th-table
in the same way as scolled-td-table" */
position: relative;
/* Truncate fixed-th-table */
overflow: hidden;
}
.fixed-th-table-wrapper td,
.fixed-th-table-wrapper th,
.scrolled-td-table-wrapper td,
.scrolled-td-table-wrapper th {
/* Set background to non-transparent color
because two tables are one above another.
*/
background: white;
}
.fixed-th-table-wrapper {
/* Make table out of flow */
position: absolute;
}
.fixed-th-table-wrapper th {
/* Place fixed-th-table th-cells above
scrolled-td-table td-cells.
*/
position: relative;
z-index: 1;
}
.scrolled-td-table-wrapper td {
/* Place scrolled-td-table td-cells
above fixed-th-table.
*/
position: relative;
}
.scrolled-td-table-wrapper {
/* Make horizonal scrollbar if needed */
overflow-x: auto;
}
/* Simulating border-collapse: collapse,
because fixed-th-table borders
are below ".scrolling-td-wrapper table" borders
*/
table {
border-spacing: 0;
}
td, th {
border-style: solid;
border-color: black;
border-width: 1px 1px 0 0;
}
th:first-child {
border-left-width: 1px;
}
tr:last-child td,
tr:last-child th {
border-bottom-width: 1px;
}
/* Unimportant styles */
.container {
width: 250px;
}
td, th {
padding: 5px;
}
</style>
</head>
<body>
<div class="container">
<div class="fixed-th-table-wrapper">
<!-- fixed-th-table -->
<table>
<tr>
<th>aaaaaaa</th>
<td>ccccccccccc asdsad asd as</td>
<td>ccccccccccc asdsad asd as</td>
</tr>
<tr>
<th>cccccccc</th>
<td>xxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyy zzzzzzzzzzzzz</td>
<td>xxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyy zzzzzzzzzzzzz</td>
</tr>
</table>
</div>
<div class="scrolled-td-table-wrapper">
<!-- scrolled-td-table
- same as fixed-th-table -->
<table>
<tr>
<th>aaaaaaa</th>
<td>ccccccccccc asdsad asd as</td>
<td>ccccccccccc asdsad asd as</td>
</tr>
<tr>
<th>cccccccc</th>
<td>xxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyy zzzzzzzzzzzzz</td>
<td>xxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyy zzzzzzzzzzzzz</td>
</tr>
</table>
</div>
</div>
</body>
</html>
Style the left column with position: fixed
. (You'll presumably want to use top
and left
styles to control where exactly it occurs.)
This is an interesting jQuery plugin that creates fixed headers and/or columns. Toggle fixed column to be true on the demo page to see it in action.
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 {_x000D_
width: 400px;_x000D_
overflow-x: scroll;_x000D_
margin-bottom: 10px;_x000D_
border: solid black 1px;_x000D_
}_x000D_
_x000D_
.tscroll table td:first-child {_x000D_
position: sticky;_x000D_
left: 0;_x000D_
background-color: #ddd;_x000D_
}_x000D_
_x000D_
.tscroll td, .tscroll th {_x000D_
border-bottom: dashed #888 1px;_x000D_
}
_x000D_
<html>_x000D_
<div class="tscroll">_x000D_
<table>_x000D_
<thead>_x000D_
<tr>_x000D_
<th></th>_x000D_
<th colspan="5">Heading 1</th>_x000D_
<th colspan="8">Heading 2</th>_x000D_
<th colspan="4">Heading 3</th>_x000D_
</tr>_x000D_
</thead>_x000D_
<tbody>_x000D_
<tr>_x000D_
<td>9:00</td>_x000D_
<td>AAA</td>_x000D_
<td>BBB</td>_x000D_
<td>CCC</td>_x000D_
<td>DDD</td>_x000D_
<td>EEE</td>_x000D_
<td>FFF</td>_x000D_
<td>GGG</td>_x000D_
<td>HHH</td>_x000D_
<td>III</td>_x000D_
<td>JJJ</td>_x000D_
<td>KKK</td>_x000D_
<td>LLL</td>_x000D_
<td>MMM</td>_x000D_
<td>NNN</td>_x000D_
<td>OOO</td>_x000D_
<td>PPP</td>_x000D_
<td>QQQ</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>10:00</td>_x000D_
<td>AAA</td>_x000D_
<td>BBB</td>_x000D_
<td>CCC</td>_x000D_
<td>DDD</td>_x000D_
<td>EEE</td>_x000D_
<td>FFF</td>_x000D_
<td>GGG</td>_x000D_
<td>HHH</td>_x000D_
<td>III</td>_x000D_
<td>JJJ</td>_x000D_
<td>KKK</td>_x000D_
<td>LLL</td>_x000D_
<td>MMM</td>_x000D_
<td>NNN</td>_x000D_
<td>OOO</td>_x000D_
<td>PPP</td>_x000D_
<td>QQQ</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>11:00</td>_x000D_
<td>AAA</td>_x000D_
<td>BBB</td>_x000D_
<td>CCC</td>_x000D_
<td>DDD</td>_x000D_
<td>EEE</td>_x000D_
<td>FFF</td>_x000D_
<td>GGG</td>_x000D_
<td>HHH</td>_x000D_
<td>III</td>_x000D_
<td>JJJ</td>_x000D_
<td>KKK</td>_x000D_
<td>LLL</td>_x000D_
<td>MMM</td>_x000D_
<td>NNN</td>_x000D_
<td>OOO</td>_x000D_
<td>PPP</td>_x000D_
<td>QQQ</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>12:00</td>_x000D_
<td>AAA</td>_x000D_
<td>BBB</td>_x000D_
<td>CCC</td>_x000D_
<td>DDD</td>_x000D_
<td>EEE</td>_x000D_
<td>FFF</td>_x000D_
<td>GGG</td>_x000D_
<td>HHH</td>_x000D_
<td>III</td>_x000D_
<td>JJJ</td>_x000D_
<td>KKK</td>_x000D_
<td>LLL</td>_x000D_
<td>MMM</td>_x000D_
<td>NNN</td>_x000D_
<td>OOO</td>_x000D_
<td>PPP</td>_x000D_
<td>QQQ</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>13:00</td>_x000D_
<td>AAA</td>_x000D_
<td>BBB</td>_x000D_
<td>CCC</td>_x000D_
<td>DDD</td>_x000D_
<td>EEE</td>_x000D_
<td>FFF</td>_x000D_
<td>GGG</td>_x000D_
<td>HHH</td>_x000D_
<td>III</td>_x000D_
<td>JJJ</td>_x000D_
<td>KKK</td>_x000D_
<td>LLL</td>_x000D_
<td>MMM</td>_x000D_
<td>NNN</td>_x000D_
<td>OOO</td>_x000D_
<td>PPP</td>_x000D_
<td>QQQ</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>14:00</td>_x000D_
<td>AAA</td>_x000D_
<td>BBB</td>_x000D_
<td>CCC</td>_x000D_
<td>DDD</td>_x000D_
<td>EEE</td>_x000D_
<td>FFF</td>_x000D_
<td>GGG</td>_x000D_
<td>HHH</td>_x000D_
<td>III</td>_x000D_
<td>JJJ</td>_x000D_
<td>KKK</td>_x000D_
<td>LLL</td>_x000D_
<td>MMM</td>_x000D_
<td>NNN</td>_x000D_
<td>OOO</td>_x000D_
<td>PPP</td>_x000D_
<td>QQQ</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>15:00</td>_x000D_
<td>AAA</td>_x000D_
<td>BBB</td>_x000D_
<td>CCC</td>_x000D_
<td>DDD</td>_x000D_
<td>EEE</td>_x000D_
<td>FFF</td>_x000D_
<td>GGG</td>_x000D_
<td>HHH</td>_x000D_
<td>III</td>_x000D_
<td>JJJ</td>_x000D_
<td>KKK</td>_x000D_
<td>LLL</td>_x000D_
<td>MMM</td>_x000D_
<td>NNN</td>_x000D_
<td>OOO</td>_x000D_
<td>PPP</td>_x000D_
<td>QQQ</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>16:00</td>_x000D_
<td>AAA</td>_x000D_
<td>BBB</td>_x000D_
<td>CCC</td>_x000D_
<td>DDD</td>_x000D_
<td>EEE</td>_x000D_
<td>FFF</td>_x000D_
<td>GGG</td>_x000D_
<td>HHH</td>_x000D_
<td>III</td>_x000D_
<td>JJJ</td>_x000D_
<td>KKK</td>_x000D_
<td>LLL</td>_x000D_
<td>MMM</td>_x000D_
<td>NNN</td>_x000D_
<td>OOO</td>_x000D_
<td>PPP</td>_x000D_
<td>QQQ</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>17:00</td>_x000D_
<td>AAA</td>_x000D_
<td>BBB</td>_x000D_
<td>CCC</td>_x000D_
<td>DDD</td>_x000D_
<td>EEE</td>_x000D_
<td>FFF</td>_x000D_
<td>GGG</td>_x000D_
<td>HHH</td>_x000D_
<td>III</td>_x000D_
<td>JJJ</td>_x000D_
<td>KKK</td>_x000D_
<td>LLL</td>_x000D_
<td>MMM</td>_x000D_
<td>NNN</td>_x000D_
<td>OOO</td>_x000D_
<td>PPP</td>_x000D_
<td>QQQ</td>_x000D_
</tr>_x000D_
</tbody>_x000D_
</table>_x000D_
</div>
_x000D_
//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>;
}
Here is another modification of the most popular answer, but with handling of variable length of text in the first column labels: http://jsfiddle.net/ozx56n41/
Basically, I'm using the second column for creating row height, like was mentioned. But my fiddle actually works unlike most mentioned above.
HTML:
<div id="outerdiv">
<div id="innerdiv">
<table>
<tr>
<td class="headcol"><div>This is a long label</div></td>
<td class="hiddenheadcol"><div>This is a long label</div></td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol"><div>Short label</div></td>
<td class="hiddenheadcol"><div>Short label</div></td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
</table>
</div>
</div>
CSS:
body {
font: 16px Calibri;
}
#outerdiv {
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100%;
border-top: 1px solid grey;
}
#innerdiv {
overflow-x: scroll;
margin-left: 100px;
overflow-y: visible;
padding-bottom: 1px;
}
table {
border-collapse:separate;
}
td {
margin: 0;
border: 1px solid grey;
border-top-width: 0;
border-left-width: 0px;
padding: 10px;
}
td.headcol {
/* Frozen 1st column */
position: absolute;
left: 0;
top: auto;
border-bottom-width: 1px;
padding: 0;
border-left-width: 1px;
}
td.hiddenheadcol {
/* Hidden 2nd column to create height */
max-width: 0;
visibility: hidden;
padding: 0;
}
td.headcol div {
/* Text container in the 1st column */
width: 100px;
max-width: 100px;
background: lightblue;
padding: 10px;
box-sizing: border-box;
}
td.hiddenheadcol div {
/* Text container in the 2nd column */
width: 100px;
max-width: 100px;
background: red;
padding: 10px;
}
td.long {
background:yellow;
letter-spacing:1em;
}
Add this in the head:
<link rel="stylesheet" type="text/css" href="/path/to/easyscrolltable.css">
<script src="/path/to/easyscrolltable.js"></script>
Javascript:
$('table.ytable').EasyScrollableTable({
'top' : 1,
'left' : 1,
'class': '',
'width': '100%',
'height': 'auto',
'footer': false,
'hover': true
});
I took Earmon Nerbonne's answer and edited it to work with tables that fill the whole width.
<!DOCTYPE html>
<html><head><title>testdoc</title>
<style type="text/css">
body {
font:16px Calibri;
}
table {
border-collapse:separate;
border-top: 3px solid grey;
}
td {
margin:0;
border:3px solid grey;
border-top-width:0px;
white-space:nowrap;
}
#outerdiv {
position: absolute;
top: 0;
left: 0;
right: 5em;
}
#innerdiv {
width: 100%;
overflow-x:scroll;
margin-left: 5em;
overflow-y:visible;
padding-bottom:1px;
}
.headcol {
position:absolute;
width:5em;
left:0;
top:auto;
border-right: 0px none black;
border-top-width:3px;
/*only relevant for first row*/
margin-top:-3px;
/*compensate for top border*/
}
.headcol:before {
content:'Row ';
}
.long {
background:yellow;
letter-spacing:1em;
}
</style></head><body>
<div id="outerdiv">
<div id="innerdiv">
<table>
<tr>
<td class="headcol">1</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">2</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">3</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">4</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">5</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">6</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">7</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">8</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">9</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
</table>
</div></div>
</body></html>
The width of the fixed column still needs to be a set value though.
$(document).ready(function() {_x000D_
var table = $('#example').DataTable( {_x000D_
scrollY: "400px",_x000D_
scrollX: true,_x000D_
scrollCollapse: true,_x000D_
paging: true,_x000D_
fixedColumns: {_x000D_
leftColumns: 3_x000D_
}_x000D_
} );_x000D_
} );
_x000D_
<head>_x000D_
<title>table</title>_x000D_
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>_x000D_
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css">_x000D_
<link rel="stylesheet" href="https://cdn.datatables.net/fixedcolumns/3.2.4/css/fixedColumns.dataTables.min.css">_x000D_
<script type="text/javascript" src="http://cdn.datatables.net/1.10.2/js/jquery.dataTables.min.js"></script>_x000D_
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>_x000D_
<script type="text/javascript" src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>_x000D_
<script type="text/javascript" src="https://cdn.datatables.net/fixedcolumns/3.2.4/js/dataTables.fixedColumns.min.js"></script>_x000D_
_x000D_
_x000D_
<style>_x000D_
th, td { white-space: nowrap; }_x000D_
div.dataTables_wrapper {_x000D_
width: 900px;_x000D_
margin: 0 auto;_x000D_
}_x000D_
</style>_x000D_
_x000D_
</head>
_x000D_
<table id="example" class="stripe row-border order-column" style="width:100%">_x000D_
<thead>_x000D_
<tr>_x000D_
<th>First name</th>_x000D_
<th>Last name</th>_x000D_
<th>Position</th>_x000D_
<th>Office</th>_x000D_
<th>Age</th>_x000D_
<th>Start date</th>_x000D_
<th>Salary</th>_x000D_
<th>Extn.</th>_x000D_
<th>E-mail</th>_x000D_
</tr>_x000D_
</thead>_x000D_
<tbody>_x000D_
<tr>_x000D_
<td>Tiger</td>_x000D_
<td>Nixon</td>_x000D_
<td>System Architect</td>_x000D_
<td>Edinburgh</td>_x000D_
<td>61</td>_x000D_
<td>2011/04/25</td>_x000D_
<td>$320,800</td>_x000D_
<td>5421</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Garrett</td>_x000D_
<td>Winters</td>_x000D_
<td>Accountant</td>_x000D_
<td>Tokyo</td>_x000D_
<td>63</td>_x000D_
<td>2011/07/25</td>_x000D_
<td>$170,750</td>_x000D_
<td>8422</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Ashton</td>_x000D_
<td>Cox</td>_x000D_
<td>Junior Technical Author</td>_x000D_
<td>San Francisco</td>_x000D_
<td>66</td>_x000D_
<td>2009/01/12</td>_x000D_
<td>$86,000</td>_x000D_
<td>1562</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Cedric</td>_x000D_
<td>Kelly</td>_x000D_
<td>Senior Javascript Developer</td>_x000D_
<td>Edinburgh</td>_x000D_
<td>22</td>_x000D_
<td>2012/03/29</td>_x000D_
<td>$433,060</td>_x000D_
<td>6224</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Airi</td>_x000D_
<td>Satou</td>_x000D_
<td>Accountant</td>_x000D_
<td>Tokyo</td>_x000D_
<td>33</td>_x000D_
<td>2008/11/28</td>_x000D_
<td>$162,700</td>_x000D_
<td>5407</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Brielle</td>_x000D_
<td>Williamson</td>_x000D_
<td>Integration Specialist</td>_x000D_
<td>New York</td>_x000D_
<td>61</td>_x000D_
<td>2012/12/02</td>_x000D_
<td>$372,000</td>_x000D_
<td>4804</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Herrod</td>_x000D_
<td>Chandler</td>_x000D_
<td>Sales Assistant</td>_x000D_
<td>San Francisco</td>_x000D_
<td>59</td>_x000D_
<td>2012/08/06</td>_x000D_
<td>$137,500</td>_x000D_
<td>9608</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Rhona</td>_x000D_
<td>Davidson</td>_x000D_
<td>Integration Specialist</td>_x000D_
<td>Tokyo</td>_x000D_
<td>55</td>_x000D_
<td>2010/10/14</td>_x000D_
<td>$327,900</td>_x000D_
<td>6200</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Colleen</td>_x000D_
<td>Hurst</td>_x000D_
<td>Javascript Developer</td>_x000D_
<td>San Francisco</td>_x000D_
<td>39</td>_x000D_
<td>2009/09/15</td>_x000D_
<td>$205,500</td>_x000D_
<td>2360</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Sonya</td>_x000D_
<td>Frost</td>_x000D_
<td>Software Engineer</td>_x000D_
<td>Edinburgh</td>_x000D_
<td>23</td>_x000D_
<td>2008/12/13</td>_x000D_
<td>$103,600</td>_x000D_
<td>1667</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Jena</td>_x000D_
<td>Gaines</td>_x000D_
<td>Office Manager</td>_x000D_
<td>London</td>_x000D_
<td>30</td>_x000D_
<td>2008/12/19</td>_x000D_
<td>$90,560</td>_x000D_
<td>3814</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Sakura</td>_x000D_
<td>Yamamoto</td>_x000D_
<td>Support Engineer</td>_x000D_
<td>Tokyo</td>_x000D_
<td>37</td>_x000D_
<td>2009/08/19</td>_x000D_
<td>$139,575</td>_x000D_
<td>9383</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Thor</td>_x000D_
<td>Walton</td>_x000D_
<td>Developer</td>_x000D_
<td>New York</td>_x000D_
<td>61</td>_x000D_
<td>2013/08/11</td>_x000D_
<td>$98,540</td>_x000D_
<td>8327</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Finn</td>_x000D_
<td>Camacho</td>_x000D_
<td>Support Engineer</td>_x000D_
<td>San Francisco</td>_x000D_
<td>47</td>_x000D_
<td>2009/07/07</td>_x000D_
<td>$87,500</td>_x000D_
<td>2927</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Serge</td>_x000D_
<td>Baldwin</td>_x000D_
<td>Data Coordinator</td>_x000D_
<td>Singapore</td>_x000D_
<td>64</td>_x000D_
<td>2012/04/09</td>_x000D_
<td>$138,575</td>_x000D_
<td>8352</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Zenaida</td>_x000D_
<td>Frank</td>_x000D_
<td>Software Engineer</td>_x000D_
<td>New York</td>_x000D_
<td>63</td>_x000D_
<td>2010/01/04</td>_x000D_
<td>$125,250</td>_x000D_
<td>7439</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Zorita</td>_x000D_
<td>Serrano</td>_x000D_
<td>Software Engineer</td>_x000D_
<td>San Francisco</td>_x000D_
<td>56</td>_x000D_
<td>2012/06/01</td>_x000D_
<td>$115,000</td>_x000D_
<td>4389</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Jennifer</td>_x000D_
<td>Acosta</td>_x000D_
<td>Junior Javascript Developer</td>_x000D_
<td>Edinburgh</td>_x000D_
<td>43</td>_x000D_
<td>2013/02/01</td>_x000D_
<td>$75,650</td>_x000D_
<td>3431</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Cara</td>_x000D_
<td>Stevens</td>_x000D_
<td>Sales Assistant</td>_x000D_
<td>New York</td>_x000D_
<td>46</td>_x000D_
<td>2011/12/06</td>_x000D_
<td>$145,600</td>_x000D_
<td>3990</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Hermione</td>_x000D_
<td>Butler</td>_x000D_
<td>Regional Director</td>_x000D_
<td>London</td>_x000D_
<td>47</td>_x000D_
<td>2011/03/21</td>_x000D_
<td>$356,250</td>_x000D_
<td>1016</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Lael</td>_x000D_
<td>Greer</td>_x000D_
<td>Systems Administrator</td>_x000D_
<td>London</td>_x000D_
<td>21</td>_x000D_
<td>2009/02/27</td>_x000D_
<td>$103,500</td>_x000D_
<td>6733</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Jonas</td>_x000D_
<td>Alexander</td>_x000D_
<td>Developer</td>_x000D_
<td>San Francisco</td>_x000D_
<td>30</td>_x000D_
<td>2010/07/14</td>_x000D_
<td>$86,500</td>_x000D_
<td>8196</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Shad</td>_x000D_
<td>Decker</td>_x000D_
<td>Regional Director</td>_x000D_
<td>Edinburgh</td>_x000D_
<td>51</td>_x000D_
<td>2008/11/13</td>_x000D_
<td>$183,000</td>_x000D_
<td>6373</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Michael</td>_x000D_
<td>Bruce</td>_x000D_
<td>Javascript Developer</td>_x000D_
<td>Singapore</td>_x000D_
<td>29</td>_x000D_
<td>2011/06/27</td>_x000D_
<td>$183,000</td>_x000D_
<td>5384</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<td>Donna</td>_x000D_
<td>Snider</td>_x000D_
<td>Customer Support</td>_x000D_
<td>New York</td>_x000D_
<td>27</td>_x000D_
<td>2011/01/25</td>_x000D_
<td>$112,000</td>_x000D_
<td>4226</td>_x000D_
<td>[email protected]</td>_x000D_
</tr>_x000D_
</tbody>_x000D_
</table>
_x000D_
This can be easily done with the help of datatables. People who are new to data tables, please refer to https://datatables.net/ .Its a plugin and offers a lot of features.In the the code given, header is fixed,first 3 columns are fixed and several other features are also there.
In HTML5, you can use CSS style.transform
.
However, i reccomend you "swipe between pages" turn off If you implement on Mac.
let l = 0;_x000D_
let t = 0;_x000D_
_x000D_
const MouseWheelHandler = (e) => {_x000D_
// vertical scroll_x000D_
if (e.deltaX == -0) {_x000D_
// t = t - e.deltaY_x000D_
_x000D_
// horizonal scroll_x000D_
} else if (e.deltaY == -0) {_x000D_
l = l - e.deltaX_x000D_
if (l >= 0) {_x000D_
l = 0;_x000D_
document.getElementById("gantt_task").style.transform = "translateX(1px)"_x000D_
document.getElementById("gantt_task_header").style.transform = "translateX(1px)"_x000D_
return false_x000D_
} _x000D_
document.getElementById("gantt_task").style.transform = "translateX(" + l.toString() + "px)"_x000D_
document.getElementById("gantt_task_header").style.transform = "translateX(" + l.toString() + "px)"_x000D_
}_x000D_
return false;_x000D_
}_x000D_
_x000D_
window.addEventListener("wheel", MouseWheelHandler, false);
_x000D_
.row {_x000D_
border-bottom: 1px solid #979A9A_x000D_
}_x000D_
#gantt_grid_header {_x000D_
height: 30px;_x000D_
width: 100px;_x000D_
position: fixed;_x000D_
z-index: 3;_x000D_
top: 0px;_x000D_
left: 0px;_x000D_
border: 1px solid #cecece;_x000D_
background-color: #F08080;_x000D_
} _x000D_
_x000D_
#gantt_task_header {_x000D_
height: 30px;_x000D_
width: 400px;_x000D_
position: fixed;_x000D_
z-index: 2;_x000D_
top: 0px;_x000D_
left: 100px;_x000D_
border: 1px solid #cecece;_x000D_
background-color: #FFC300;_x000D_
}_x000D_
_x000D_
#gantt_grid {_x000D_
width: 100px; _x000D_
height: 400px;_x000D_
position: absolute;_x000D_
left: 0px;_x000D_
top: 0px;_x000D_
z-index: 1;_x000D_
border: 1px solid #cecece;_x000D_
background-color: #DAF7A6;_x000D_
}_x000D_
_x000D_
#gantt_task {_x000D_
width: 400px; _x000D_
height: 400px;_x000D_
position: absolute;_x000D_
left: 100px;_x000D_
top: 0px;_x000D_
border: 1px solid #cecece;_x000D_
background-color: #FF5733;_x000D_
}
_x000D_
<html>_x000D_
<div id="gantt_grid_header">_x000D_
HEADER_x000D_
</div>_x000D_
<div id="gantt_grid">_x000D_
<div class="row">V Scroll OK</div>_x000D_
<div class="row">V Scroll OK</div>_x000D_
<div class="row">V Scroll OK</div>_x000D_
<div class="row">V Scroll OK</div>_x000D_
<div class="row">V Scroll OK</div>_x000D_
<div class="row">V Scroll OK</div>_x000D_
<div class="row">V Scroll OK</div>_x000D_
<div class="row">V Scroll OK</div>_x000D_
<div class="row">V Scroll OK</div>_x000D_
</div>_x000D_
<div id="gantt_task_header">_x000D_
DATA HEADER_x000D_
</div>_x000D_
<div id="gantt_task">_x000D_
<div class="row">Vertical,Horizenal Scroll OK</div>_x000D_
<div class="row">Vertical,Horizenal Scroll OK</div>_x000D_
<div class="row">Vertical,Horizenal Scroll OK</div>_x000D_
<div class="row">Vertical,Horizenal Scroll OK</div>_x000D_
<div class="row">Vertical,Horizenal Scroll OK</div>_x000D_
<div class="row">Vertical,Horizenal Scroll OK</div>_x000D_
<div class="row">Vertical,Horizenal Scroll OK</div>_x000D_
<div class="row">Vertical,Horizenal Scroll OK</div>_x000D_
<div class="row">Vertical,Horizenal Scroll OK</div>_x000D_
</div>_x000D_
</html>
_x000D_
If you're in Webdevelopper hell and need to make this work for IE6, here's a sample code I used:
<html>
<head>
<style type="text/css">
.fixme {
position: relative;
left: expression( ( 20 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
background-color: #FFFFFF;
}
</style>
</head>
<body>
<table width="1500px" border="2">
<tr>
<td class="fixme" style="width: 200px;">loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet</td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
</tr>
<tr>
<td class="fixme" style="width: 200px;">loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
</tr>
<tr>
<td class="fixme" style="width: 200px;">loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
</tr>
<tr>
<td class="fixme" style="width: 200px;">loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
<td>loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet loremp ispum dolor sit amet </td>
</tr>
</table>
</body>
</html>
This will work probably ONLY for IE6, so use conditional comments for the CSS.
Opera was buggy for all of the previous answers when I tested them on my mac. If you scroll through the table the fixed column disappears after you pass the first unfixed column. I went ahead and wrote the code below. It works in all the browsers I have locally installed. I don't know how ie handles it though.
Just keep that in mind that if you intend to skip rows in one table and not the other or change the heights of the rows you might need to adjust this code.
<table class = "fixedColumns">
<tr><td> row 1 </td></tr>
<tr><td> row 2 </td></tr>
</table>
<table class = "scrollableTable">
<tr><td> col 1 </td> <td> col 2 </td><td> col 3 </td><td> col 4 </td></tr>
<tr><td> col 1 </td> <td> col 2 </td><td> col 3 </td><td> col 4 </td></tr>
</table>
<style type = "text/css" >
.fixedColumns
{
vertical-align:top;
display: inline-block;
}
.scrollableTable
{
display: inline-block;
width:50px;
white-space: nowrap;
overflow-x: scroll;
}
</style>
For me this was the only one that worked perfectly (thanks to Paul O'Brien!): https://codepen.io/paulobrien/pen/gWoVzN
Here's the snippet:
// requires jquery library_x000D_
jQuery(document).ready(function() {_x000D_
jQuery(".main-table").clone(true).appendTo('#table-scroll').addClass('clone'); _x000D_
});
_x000D_
.table-scroll {_x000D_
position:relative;_x000D_
max-width:600px;_x000D_
margin:auto;_x000D_
overflow:hidden;_x000D_
border:1px solid #000;_x000D_
}_x000D_
.table-wrap {_x000D_
width:100%;_x000D_
overflow:auto;_x000D_
}_x000D_
.table-scroll table {_x000D_
width:100%;_x000D_
margin:auto;_x000D_
border-collapse:separate;_x000D_
border-spacing:0;_x000D_
}_x000D_
.table-scroll th, .table-scroll td {_x000D_
padding:5px 10px;_x000D_
border:1px solid #000;_x000D_
background:#fff;_x000D_
white-space:nowrap;_x000D_
vertical-align:top;_x000D_
}_x000D_
.table-scroll thead, .table-scroll tfoot {_x000D_
background:#f9f9f9;_x000D_
}_x000D_
.clone {_x000D_
position:absolute;_x000D_
top:0;_x000D_
left:0;_x000D_
pointer-events:none;_x000D_
}_x000D_
.clone th, .clone td {_x000D_
visibility:hidden_x000D_
}_x000D_
.clone td, .clone th {_x000D_
border-color:transparent_x000D_
}_x000D_
.clone tbody th {_x000D_
visibility:visible;_x000D_
color:red;_x000D_
}_x000D_
.clone .fixed-side {_x000D_
border:1px solid #000;_x000D_
background:#eee;_x000D_
visibility:visible;_x000D_
}_x000D_
.clone thead, .clone tfoot{background:transparent;}
_x000D_
<div id="table-scroll" class="table-scroll">_x000D_
<div class="table-wrap">_x000D_
<table class="main-table">_x000D_
<thead>_x000D_
<tr>_x000D_
<th class="fixed-side" scope="col"> </th>_x000D_
<th scope="col">Header 2</th>_x000D_
<th scope="col">Header 3</th>_x000D_
<th scope="col">Header 4</th>_x000D_
<th scope="col">Header 5</th>_x000D_
<th scope="col">Header 6</th>_x000D_
<th scope="col">Header 7</th>_x000D_
<th scope="col">Header 8</th>_x000D_
</tr>_x000D_
</thead>_x000D_
<tbody>_x000D_
<tr>_x000D_
<th class="fixed-side">Left Column</th>_x000D_
<td>Cell content<br>_x000D_
test</td>_x000D_
<td><a href="#">Cell content longer</a></td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<th class="fixed-side">Left Column</th>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content longer</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<th class="fixed-side">Left Column</th>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content longer</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<th class="fixed-side">Left Column</th>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content longer</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<th class="fixed-side">Left Column</th>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content longer</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
</tr>_x000D_
<tr>_x000D_
<th class="fixed-side">Left Column</th>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content longer</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
<td>Cell content</td>_x000D_
</tr>_x000D_
</tbody>_x000D_
<tfoot>_x000D_
<tr>_x000D_
<th class="fixed-side"> </th>_x000D_
<td>Footer 2</td>_x000D_
<td>Footer 3</td>_x000D_
<td>Footer 4</td>_x000D_
<td>Footer 5</td>_x000D_
<td>Footer 6</td>_x000D_
<td>Footer 7</td>_x000D_
<td>Footer 8</td>_x000D_
</tr>_x000D_
</tfoot>_x000D_
</table>_x000D_
</div>_x000D_
</div>_x000D_
_x000D_
<p>See <a href="https://codepen.io/paulobrien/pen/LBrMxa" target="blank">position Sticky version </a>with no JS</p>_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js" type="text/javascript"></script>
_x000D_
No need to add any plugin, CSS can do this job !!!
The idea is to make the position of all the first cells in each column absolute, and make width fixed. Ex:
max-width: 125px;
min-width: 125px;
position: absolute;
This hides some parts of some columns under the first column, so add an empty second column (add second empty td) with width same as the first column.
I tested and this works in Chrome and Firefox.
You can use sticky
position.
Here is a sample code. This is HTML/CSS solution. No js is required.
.view {
margin: auto;
width: 600px;
}
.wrapper {
position: relative;
overflow: auto;
border: 1px solid black;
white-space: nowrap;
}
.sticky-col {
position: -webkit-sticky;
position: sticky;
background-color: white;
}
.first-col {
width: 100px;
min-width: 100px;
max-width: 100px;
left: 0px;
}
.second-col {
width: 150px;
min-width: 150px;
max-width: 150px;
left: 100px;
}
_x000D_
<div class="view">
<div class="wrapper">
<table class="table">
<thead>
<tr>
<th class="sticky-col first-col">Number</th>
<th class="sticky-col second-col">First Name</th>
<th>Last Name</th>
<th>Employer</th>
</tr>
</thead>
<tbody>
<tr>
<td class="sticky-col first-col">1</td>
<td class="sticky-col second-col">Mark</td>
<td>Ham</td>
<td>Micro</td>
</tr>
<tr>
<td class="sticky-col first-col">2</td>
<td class="sticky-col second-col">Jacob</td>
<td>Smith</td>
<td>Adob Adob Adob AdobAdob Adob Adob Adob Adob</td>
</tr>
<tr>
<td class="sticky-col first-col">3</td>
<td class="sticky-col second-col">Larry</td>
<td>Wen</td>
<td>Goog Goog Goog GoogGoog Goog Goog Goog Goog Goog</td>
</tr>
</tbody>
</table>
</div>
</div>
_x000D_
Bootply code: https://www.bootply.com/g8pfBXOcY9
You can just make the first column position: sticky; z-index: 9
.
It will make the column/row stick to its current position.
Checkout my example codepen here https://codepen.io/swastikmishra/pen/zYYdKBQ
HTML Example
<style type="text/css">
table{ text-align: center; }
.table-container{ width: 500px; height: 300px; overflow: scroll;}
table th, table td {
white-space: nowrap;
padding: 10px 20px;
font-family: Arial;
}
table tr th:first-child, table td:first-child{
position: sticky;
width: 100px;
left: 0;
z-index: 10;
background: #fff;
}
table tr th:first-child{
z-index: 11;
}
table tr th{
position: sticky;
top: 0;
z-index: 9;
background: #fff;
}
</style>
<div class="table-container">
<table>
<tr><th>Hello World</th><th>Hello World</th><th>Hello World</th><th>Hello World</th><th>Hello World</th><th>Hello World</th><th>Hello World</th></tr>
<tr><td>H11</td><td>H12</td><td>H13</td><td>H14</td><td>H15</td><td>H16</td><td>H17</td></tr>
<tr><td>H21</td><td>H22</td><td>H23</td><td>H24</td><td>H25</td><td>H26</td><td>H27</td></tr>
<tr><td>H31</td><td>H32</td><td>H33</td><td>H34</td><td>H35</td><td>H36</td><td>H37</td></tr>
<tr><td>H41</td><td>H42</td><td>H44</td><td>H44</td><td>H45</td><td>H46</td><td>H47</td></tr>
<tr><td>H51</td><td>H52</td><td>H54</td><td>H54</td><td>H55</td><td>H56</td><td>H57</td></tr>
<tr><td>H61</td><td>H62</td><td>H64</td><td>H64</td><td>H65</td><td>H66</td><td>H67</td></tr>
<tr><td>H71</td><td>H72</td><td>H74</td><td>H74</td><td>H75</td><td>H76</td><td>H77</td></tr>
<tr><td>H81</td><td>H82</td><td>H84</td><td>H84</td><td>H85</td><td>H86</td><td>H87</td></tr>
</table>
</div>
Source: Stackoverflow.com