How do I create an HTML table with a fixed/frozen left column and a scrollable body?
HtmlCssHtml TableHtml Problem Overview
I need a simple solution. I know it's similar to some other questions, like:
- https://stackoverflow.com/questions/684211/html-table-with-fixed-headers-and-a-fixed-column
- https://stackoverflow.com/questions/296020/how-can-i-lock-the-first-row-and-first-column-of-a-table-when-scrolling-possibly
But I need just a single left column to be frozen and I would prefer a simple and script-less solution.
Html Solutions
Solution 1 - Html
If you want a table where only the columns scroll horizontally, you can position: absolute
the first column (and specify its width explicitly), and then wrap the entire table in an overflow-x: scroll
block. Don't bother trying this in IE7, however...
Relevant HTML & CSS:
table {
border-collapse: separate;
border-spacing: 0;
border-top: 1px solid grey;
}
td,
th {
margin: 0;
border: 1px solid grey;
white-space: nowrap;
border-top-width: 0px;
}
div {
width: 500px;
overflow-x: scroll;
margin-left: 5em;
overflow-y: visible;
padding: 0;
}
.headcol {
position: absolute;
width: 5em;
left: 0;
top: auto;
border-top-width: 1px;
/*only relevant for first row*/
margin-top: -1px;
/*compensate for top border*/
}
.headcol:before {
content: 'Row ';
}
.long {
background: yellow;
letter-spacing: 1em;
}
<div>
<table>
<tr>
<th class="headcol">1</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">2</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">3</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">4</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">5</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<th class="headcol">6</th>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
</table>
</div>
Solution 2 - Html
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;
}
<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>
codeply code: https://www.codeply.com/p/oZ4NjpvwbO
Solution 3 - Html
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: #ddd;
}
.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>
Solution 4 - Html
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.
Solution 5 - Html
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>
Solution 6 - Html
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,
.table-fixed-right table {
border-collapse: collapse;
}
.table-fixed-right td,
.table-fixed-right th,
.table-fixed-left td,
.table-fixed-left th {
border: 1px solid #ddd;
padding: 5px 5px;
}
.table-fixed-left {
width: 120px;
float: left;
position: fixed;
overflow-x: scroll;
white-space: nowrap;
text-align: left;
border: 1px solid #ddd;
z-index: 2;
}
.table-fixed-right {
width: calc(100% - 145px);
right: 15px;
position: fixed;
overflow-x: scroll;
border: 1px solid #ddd;
white-space: nowrap;
}
.table-fixed-right td,
.table-fixed-right th {
padding: 5px 10px;
}
<div class="table-fixed-left">
<table>
<tr>
<th>Normal Header</th>
</tr>
<tr>
<th>Header with extra line
<br/> </th>
</tr>
<tr>
<th>Normal Header</th>
</tr>
<tr>
<th>Normal with extra line
<br/> </th>
</tr>
<tr>
<th>Normal Header</th>
</tr>
<tr>
<th>Normal Header</th>
</tr>
</table>
</div>
<div class="table-fixed-right">
<table>
<tr>
<th>Header</th>
<th>Another header</th>
<th>Header</th>
<th>Header really really really really long</th>
</tr>
<tr>
<td>Info Long</td>
<td>Info
<br/>with second line</td>
<td>Info
<br/>with second line</td>
<td>Info Long</td>
</tr>
<tr>
<td>Info Long</td>
<td>Info Long</td>
<td>Info Long</td>
<td>Info Long</td>
</tr>
<tr>
<td>Info
<br/>with second line</td>
<td>Info
<br/>with second line</td>
<td>Info
<br/>with second line</td>
<td>Info</td>
</tr>
<tr>
<td>Info</td>
<td>Info</td>
<td>Info</td>
<td>Info</td>
</tr>
<tr>
<td>Info</td>
<td>Info</td>
<td>Info</td>
<td>Info</td>
</tr>
</table>
</div>
Hope this helps someone!
Solution 7 - Html
Style the left column with position: fixed
. (You'll presumably want to use top
and left
styles to control where exactly it occurs.)
Solution 8 - Html
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
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;
}
<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>
Solution 9 - Html
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.
Solution 10 - Html
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>
Solution 11 - Html
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.
Solution 12 - Html
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.
Solution 13 - Html
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;
Solution 14 - Html
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;
}
Solution 15 - Html
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
jQuery(document).ready(function() {
jQuery(".main-table").clone(true).appendTo('#table-scroll').addClass('clone');
});
.table-scroll {
position:relative;
max-width:600px;
margin:auto;
overflow:hidden;
border:1px solid #000;
}
.table-wrap {
width:100%;
overflow:auto;
}
.table-scroll table {
width:100%;
margin:auto;
border-collapse:separate;
border-spacing:0;
}
.table-scroll th, .table-scroll td {
padding:5px 10px;
border:1px solid #000;
background:#fff;
white-space:nowrap;
vertical-align:top;
}
.table-scroll thead, .table-scroll tfoot {
background:#f9f9f9;
}
.clone {
position:absolute;
top:0;
left:0;
pointer-events:none;
}
.clone th, .clone td {
visibility:hidden
}
.clone td, .clone th {
border-color:transparent
}
.clone tbody th {
visibility:visible;
color:red;
}
.clone .fixed-side {
border:1px solid #000;
background:#eee;
visibility:visible;
}
.clone thead, .clone tfoot{background:transparent;}
<div id="table-scroll" class="table-scroll">
<div class="table-wrap">
<table class="main-table">
<thead>
<tr>
<th class="fixed-side" scope="col"> </th>
<th scope="col">Header 2</th>
<th scope="col">Header 3</th>
<th scope="col">Header 4</th>
<th scope="col">Header 5</th>
<th scope="col">Header 6</th>
<th scope="col">Header 7</th>
<th scope="col">Header 8</th>
</tr>
</thead>
<tbody>
<tr>
<th class="fixed-side">Left Column</th>
<td>Cell content<br>
test</td>
<td><a href="#">Cell content longer</a></td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
</tr>
<tr>
<th class="fixed-side">Left Column</th>
<td>Cell content</td>
<td>Cell content longer</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
</tr>
<tr>
<th class="fixed-side">Left Column</th>
<td>Cell content</td>
<td>Cell content longer</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
</tr>
<tr>
<th class="fixed-side">Left Column</th>
<td>Cell content</td>
<td>Cell content longer</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
</tr>
<tr>
<th class="fixed-side">Left Column</th>
<td>Cell content</td>
<td>Cell content longer</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
</tr>
<tr>
<th class="fixed-side">Left Column</th>
<td>Cell content</td>
<td>Cell content longer</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
<td>Cell content</td>
</tr>
</tbody>
<tfoot>
<tr>
<th class="fixed-side"> </th>
<td>Footer 2</td>
<td>Footer 3</td>
<td>Footer 4</td>
<td>Footer 5</td>
<td>Footer 6</td>
<td>Footer 7</td>
<td>Footer 8</td>
</tr>
</tfoot>
</table>
</div>
</div>
<p>See <a href="https://codepen.io/paulobrien/pen/LBrMxa" target="blank">position Sticky version </a>with no JS</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js" type="text/javascript"></script>
Solution 16 - Html
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>
Solution 17 - Html
//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>;
}
Solution 18 - Html
.div1 {
width: 600px;
height: 400px;
overflow: scroll;
border: 1px solid #777777;
}
.div1 table {
border-spacing: 0;
}
.div1 th {
border-left: none;
border-right: 1px solid #bbbbbb;
padding: 5px;
width: 80px;
min-width: 80px;
position: sticky;
top: 0;
background: #727272;
color: #e0e0e0;
font-weight: normal;
}
.div1 td {
border-left: none;
border-right: 1px solid #bbbbbb;
border-bottom: 1px solid #bbbbbb;
padding: 5px;
width: 80px;
min-width: 80px;
}
.div1 th:nth-child(1),
.div1 td:nth-child(1) {
position: sticky;
left: 0;
width: 150px;
min-width: 150px;
}
.div1 th:nth-child(2),
.div1 td:nth-child(2) {
position: sticky;
/* 1st cell left/right padding + 1st cell width + 1st cell left/right border width */
/* 0 + 5 + 150 + 5 + 1 */
left: 161px;
width: 50px;
min-width: 50px;
}
.div1 td:nth-child(1),
.div1 td:nth-child(2) {
background: #ffebb5;
}
.div1 th:nth-child(1),
.div1 th:nth-child(2) {
z-index: 2;
}
the HTML,
<div class="div1">
<table>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
<th>Column 5</th>
<th>Column 6</th>
</tr>
<tr>
<td>Row Data 1</td>
<td>Row Data 2</td>
<td>Row Data 3</td>
<td>Row Data 4</td>
<td>Row Data 5</td>
<td>Row Data 6</td>
</tr>
<tr>
<td>Row Data 1</td>
<td>Row Data 2</td>
<td>Row Data 3</td>
<td>Row Data 4</td>
<td>Row Data 5</td>
<td>Row Data 6</td>
</tr>
</table>
</div>
Youtube Video Walkthrough: https://www.youtube.com/watch?v=_dpSEjaKqSE
Example 1: Fixed width & height
https://adriancs.com/demo/freeze_table_column_row.html
Example 2: Responsive width & height (adjusted by using viewport)
https://adriancs.com/html-css-js/298/html-table-freeze-row-and-column-with-css/
Full tutorial explanation:
https://adriancs.com/demo/freeze_table_column_row_responsive_viewport.html
Solution 19 - Html
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.
Solution 20 - Html
$(document).ready(function() {
var table = $('#example').DataTable( {
scrollY: "400px",
scrollX: true,
scrollCollapse: true,
paging: true,
fixedColumns: {
leftColumns: 3
}
} );
} );
<head>
<title>table</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/fixedcolumns/3.2.4/css/fixedColumns.dataTables.min.css">
<script type="text/javascript" src="http://cdn.datatables.net/1.10.2/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/fixedcolumns/3.2.4/js/dataTables.fixedColumns.min.js"></script>
<style>
th, td { white-space: nowrap; }
div.dataTables_wrapper {
width: 900px;
margin: 0 auto;
}
</style>
</head>
<table id="example" class="stripe row-border order-column" style="width:100%">
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
<th>Extn.</th>
<th>E-mail</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger</td>
<td>Nixon</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011/04/25</td>
<td>$320,800</td>
<td>5421</td>
<td>t.nixon@datatables.net</td>
</tr>
<tr>
<td>Garrett</td>
<td>Winters</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011/07/25</td>
<td>$170,750</td>
<td>8422</td>
<td>g.winters@datatables.net</td>
</tr>
<tr>
<td>Ashton</td>
<td>Cox</td>
<td>Junior Technical Author</td>
<td>San Francisco</td>
<td>66</td>
<td>2009/01/12</td>
<td>$86,000</td>
<td>1562</td>
<td>a.cox@datatables.net</td>
</tr>
<tr>
<td>Cedric</td>
<td>Kelly</td>
<td>Senior Javascript Developer</td>
<td>Edinburgh</td>
<td>22</td>
<td>2012/03/29</td>
<td>$433,060</td>
<td>6224</td>
<td>c.kelly@datatables.net</td>
</tr>
<tr>
<td>Airi</td>
<td>Satou</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>33</td>
<td>2008/11/28</td>
<td>$162,700</td>
<td>5407</td>
<td>a.satou@datatables.net</td>
</tr>
<tr>
<td>Brielle</td>
<td>Williamson</td>
<td>Integration Specialist</td>
<td>New York</td>
<td>61</td>
<td>2012/12/02</td>
<td>$372,000</td>
<td>4804</td>
<td>b.williamson@datatables.net</td>
</tr>
<tr>
<td>Herrod</td>
<td>Chandler</td>
<td>Sales Assistant</td>
<td>San Francisco</td>
<td>59</td>
<td>2012/08/06</td>
<td>$137,500</td>
<td>9608</td>
<td>h.chandler@datatables.net</td>
</tr>
<tr>
<td>Rhona</td>
<td>Davidson</td>
<td>Integration Specialist</td>
<td>Tokyo</td>
<td>55</td>
<td>2010/10/14</td>
<td>$327,900</td>
<td>6200</td>
<td>r.davidson@datatables.net</td>
</tr>
<tr>
<td>Colleen</td>
<td>Hurst</td>
<td>Javascript Developer</td>
<td>San Francisco</td>
<td>39</td>
<td>2009/09/15</td>
<td>$205,500</td>
<td>2360</td>
<td>c.hurst@datatables.net</td>
</tr>
<tr>
<td>Sonya</td>
<td>Frost</td>
<td>Software Engineer</td>
<td>Edinburgh</td>
<td>23</td>
<td>2008/12/13</td>
<td>$103,600</td>
<td>1667</td>
<td>s.frost@datatables.net</td>
</tr>
<tr>
<td>Jena</td>
<td>Gaines</td>
<td>Office Manager</td>
<td>London</td>
<td>30</td>
<td>2008/12/19</td>
<td>$90,560</td>
<td>3814</td>
<td>j.gaines@datatables.net</td>
</tr>
<tr>
<td>Sakura</td>
<td>Yamamoto</td>
<td>Support Engineer</td>
<td>Tokyo</td>
<td>37</td>
<td>2009/08/19</td>
<td>$139,575</td>
<td>9383</td>
<td>s.yamamoto@datatables.net</td>
</tr>
<tr>
<td>Thor</td>
<td>Walton</td>
<td>Developer</td>
<td>New York</td>
<td>61</td>
<td>2013/08/11</td>
<td>$98,540</td>
<td>8327</td>
<td>t.walton@datatables.net</td>
</tr>
<tr>
<td>Finn</td>
<td>Camacho</td>
<td>Support Engineer</td>
<td>San Francisco</td>
<td>47</td>
<td>2009/07/07</td>
<td>$87,500</td>
<td>2927</td>
<td>f.camacho@datatables.net</td>
</tr>
<tr>
<td>Serge</td>
<td>Baldwin</td>
<td>Data Coordinator</td>
<td>Singapore</td>
<td>64</td>
<td>2012/04/09</td>
<td>$138,575</td>
<td>8352</td>
<td>s.baldwin@datatables.net</td>
</tr>
<tr>
<td>Zenaida</td>
<td>Frank</td>
<td>Software Engineer</td>
<td>New York</td>
<td>63</td>
<td>2010/01/04</td>
<td>$125,250</td>
<td>7439</td>
<td>z.frank@datatables.net</td>
</tr>
<tr>
<td>Zorita</td>
<td>Serrano</td>
<td>Software Engineer</td>
<td>San Francisco</td>
<td>56</td>
<td>2012/06/01</td>
<td>$115,000</td>
<td>4389</td>
<td>z.serrano@datatables.net</td>
</tr>
<tr>
<td>Jennifer</td>
<td>Acosta</td>
<td>Junior Javascript Developer</td>
<td>Edinburgh</td>
<td>43</td>
<td>2013/02/01</td>
<td>$75,650</td>
<td>3431</td>
<td>j.acosta@datatables.net</td>
</tr>
<tr>
<td>Cara</td>
<td>Stevens</td>
<td>Sales Assistant</td>
<td>New York</td>
<td>46</td>
<td>2011/12/06</td>
<td>$145,600</td>
<td>3990</td>
<td>c.stevens@datatables.net</td>
</tr>
<tr>
<td>Hermione</td>
<td>Butler</td>
<td>Regional Director</td>
<td>London</td>
<td>47</td>
<td>2011/03/21</td>
<td>$356,250</td>
<td>1016</td>
<td>h.butler@datatables.net</td>
</tr>
<tr>
<td>Lael</td>
<td>Greer</td>
<td>Systems Administrator</td>
<td>London</td>
<td>21</td>
<td>2009/02/27</td>
<td>$103,500</td>
<td>6733</td>
<td>l.greer@datatables.net</td>
</tr>
<tr>
<td>Jonas</td>
<td>Alexander</td>
<td>Developer</td>
<td>San Francisco</td>
<td>30</td>
<td>2010/07/14</td>
<td>$86,500</td>
<td>8196</td>
<td>j.alexander@datatables.net</td>
</tr>
<tr>
<td>Shad</td>
<td>Decker</td>
<td>Regional Director</td>
<td>Edinburgh</td>
<td>51</td>
<td>2008/11/13</td>
<td>$183,000</td>
<td>6373</td>
<td>s.decker@datatables.net</td>
</tr>
<tr>
<td>Michael</td>
<td>Bruce</td>
<td>Javascript Developer</td>
<td>Singapore</td>
<td>29</td>
<td>2011/06/27</td>
<td>$183,000</td>
<td>5384</td>
<td>m.bruce@datatables.net</td>
</tr>
<tr>
<td>Donna</td>
<td>Snider</td>
<td>Customer Support</td>
<td>New York</td>
<td>27</td>
<td>2011/01/25</td>
<td>$112,000</td>
<td>4226</td>
<td>d.snider@datatables.net</td>
</tr>
</tbody>
</table>
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.
Solution 21 - Html
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.
Solution 22 - Html
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.
Solution 23 - Html
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;
let t = 0;
const MouseWheelHandler = (e) => {
// vertical scroll
if (e.deltaX == -0) {
// t = t - e.deltaY
// horizonal scroll
} else if (e.deltaY == -0) {
l = l - e.deltaX
if (l >= 0) {
l = 0;
document.getElementById("gantt_task").style.transform = "translateX(1px)"
document.getElementById("gantt_task_header").style.transform = "translateX(1px)"
return false
}
document.getElementById("gantt_task").style.transform = "translateX(" + l.toString() + "px)"
document.getElementById("gantt_task_header").style.transform = "translateX(" + l.toString() + "px)"
}
return false;
}
window.addEventListener("wheel", MouseWheelHandler, false);
.row {
border-bottom: 1px solid #979A9A
}
#gantt_grid_header {
height: 30px;
width: 100px;
position: fixed;
z-index: 3;
top: 0px;
left: 0px;
border: 1px solid #cecece;
background-color: #F08080;
}
#gantt_task_header {
height: 30px;
width: 400px;
position: fixed;
z-index: 2;
top: 0px;
left: 100px;
border: 1px solid #cecece;
background-color: #FFC300;
}
#gantt_grid {
width: 100px;
height: 400px;
position: absolute;
left: 0px;
top: 0px;
z-index: 1;
border: 1px solid #cecece;
background-color: #DAF7A6;
}
#gantt_task {
width: 400px;
height: 400px;
position: absolute;
left: 100px;
top: 0px;
border: 1px solid #cecece;
background-color: #FF5733;
}
<html>
<div id="gantt_grid_header">
HEADER
</div>
<div id="gantt_grid">
<div class="row">V Scroll OK</div>
<div class="row">V Scroll OK</div>
<div class="row">V Scroll OK</div>
<div class="row">V Scroll OK</div>
<div class="row">V Scroll OK</div>
<div class="row">V Scroll OK</div>
<div class="row">V Scroll OK</div>
<div class="row">V Scroll OK</div>
<div class="row">V Scroll OK</div>
</div>
<div id="gantt_task_header">
DATA HEADER
</div>
<div id="gantt_task">
<div class="row">Vertical,Horizenal Scroll OK</div>
<div class="row">Vertical,Horizenal Scroll OK</div>
<div class="row">Vertical,Horizenal Scroll OK</div>
<div class="row">Vertical,Horizenal Scroll OK</div>
<div class="row">Vertical,Horizenal Scroll OK</div>
<div class="row">Vertical,Horizenal Scroll OK</div>
<div class="row">Vertical,Horizenal Scroll OK</div>
<div class="row">Vertical,Horizenal Scroll OK</div>
<div class="row">Vertical,Horizenal Scroll OK</div>
</div>
</html>
Solution 24 - Html
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 {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #ddd;
min-width: 600px;
}
.labels {
display:flex;
flex-direction: column
}
.overflow {
overflow-x: scroll;
min width: 400px;
flex: 1;
}
.label {
display: flex;
align-items: center;
white-space:nowrap;
padding: 10px;
flex: 1;
border-bottom: 1px solid #ddd;
border-right: 2px solid #ddd;
}
.label:last-of-type {
overflow-x: scroll;
border-bottom: 0;
}
td {
border: 1px solid #ddd;
padding: 10px;
}
.flex {
display:flex;
max-width: 600px;
padding: 0;
border: 5px solid #ddd;
}
<div class="flex">
<div class="labels">
<span class="label">Label 1</span>
<span class="label">Lorem ipsum dolor sit amet.</span>
<span class="label">Lorem ipsum dolor.</span>
</div>
<div class="overflow">
<table>
<tr>
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>
</tr>
<tr>
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>
</tr>
<tr>
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>
<td class="long">Lorem ipsum dolor sit amet consectetur adipisicing</td>
</tr>
</table>
</div>
</div>