HTML table with horizontal scrolling (first column fixed)
Asked Answered
F

7

81

I have been trying to think of a way to make a table with a fixed first column (and the rest of the table with a horizontal overflow) I saw a post which had a similar question. but the fixed column bit did not seem to be resolved. Help?

Footplate answered 4/8, 2010 at 3:6 Comment(2)
I'd like to expand this question a little: a friend of mine wants to make a table which wouldn't scale to more than 100% of the page, but would have more than two columns that together should be scrollable in case they need more horizontal space than there is. In effect, this should be similar to Frozen columns in MS Excel. Is that possible?Teyde
See my answer on similar question: https://mcmap.net/q/76004/-how-do-i-create-an-html-table-with-a-fixed-frozen-left-column-and-a-scrollable-bodyStepheniestephens
W
21

I have a similar table styled like so:

<table style="width:100%; table-layout:fixed">
  <tr>
    <td style="width: 150px">Hello, World!</td>
    <td>
      <div>
        <pre style="margin:0; overflow:scroll">My preformatted content</pre>
      </div>
    </td>
  </tr>
</table>
Winna answered 5/8, 2010 at 15:48 Comment(6)
This answer would really benefit from a demo here.Vulnerary
JSFIDDLE demo so that it's more clear what happens hereBranen
That only scrolls a single cell…Hectogram
I don't know why this is the accepted answer. The question says: and the rest of the table, which in my point of view includes more than one column...Olid
and the columns should be in sync with the headers, like if the columns scroll; headers should scroll too with the columns. But I don't think they both will be in sync after implementing this solutionPrepuce
this is best optionCharlot
C
126

How about:

table {
  table-layout: fixed; 
  width: 100%;
  *margin-left: -100px; /*ie7*/
}
td, th {
  vertical-align: top;
  border-top: 1px solid #ccc;
  padding: 10px;
  width: 100px;
}
.fix {
  position: absolute;
  *position: relative; /*ie7*/
  margin-left: -100px;
  width: 100px;
}
.outer {
  position: relative;
}
.inner {
  overflow-x: scroll;
  overflow-y: visible;
  width: 400px; 
  margin-left: 100px;
}
<div class="outer">
  <div class="inner">
    <table>
      <tr>
        <th class=fix></th>
        <th>Col 1</th>
        <th>Col 2</th>
        <th>Col 3</th>
        <th>Col 4</th>
        <th class="fix">Col 5</th>
      </tr>
      <tr>
        <th class=fix>Header A</th>
        <td>col 1 - A</td>
        <td>col 2 - A (WITH LONGER CONTENT)</td>
        <td>col 3 - A</td>
        <td>col 4 - A</td>
        <td class=fix>col 5 - A</td>
      </tr>
      <tr>
        <th class=fix>Header B</th>
        <td>col 1 - B</td>
        <td>col 2 - B</td>
        <td>col 3 - B</td>
        <td>col 4 - B</td>
        <td class=fix>col 5 - B</td>
      </tr>
      <tr>
        <th class=fix>Header C</th>
        <td>col 1 - C</td>
        <td>col 2 - C</td>
        <td>col 3 - C</td>
        <td>col 4 - C</td>
        <td class=fix>col 5 - C</td>
      </tr>
    </table>
  </div>
</div>

You can test it out in this jsbin: http://jsbin.com/uxecel/4/edit

Closed answered 23/1, 2013 at 18:22 Comment(10)
Simple but effective solution to my query!Mallemuck
This basically works for me but I'd like to start out with the right-most columns of the scrolling div visible. My column titles are dates, with the most-recent date on the far right, and I'd like that to be visible when the <table> is first displayed. Is there any way to do this programmatically? Is there a way to programmatically move the horizontal scroll bar in either direction? I'd like to have always-available "scroll left" and "scroll right" buttons at the top of the table, since the browser-supported scroll bar is at the bottom and not always immediately visible.Kenwee
I saw it has a big gap between header column and data columns when I set width of table > all data columns width,does anybody know why and how to fix it? please see here: jsbin.com/sesurutojo/edit?outputScutt
If I use paging via ajax and I have to go to next page then the scroll does not work and all the table properties are lost. How can I get the same table UI but with some ajax request?Nan
This seems to work only if vertical scrolling is not required. For my case there are many rows so scrolling vertically will only scroll the row data but not the row header fixed in this way using position absolute.Psychomancy
@Closed : how to set height for the based on content in fixed columnMcdaniels
@blahdiblah :how to set height for the based on content in fixed columnMcdaniels
what about if there is paging?Threepence
@bruce I think that vertical scrolling can work if you make the table position: relative and then put it in a div that scrolls. That way, the absolute positioning is scrolled along with the rest of the table.Hectogram
@Hectogram I using rowspan but once i use this code my rowspan doesn't work anymore. Do you know by any chance inner or outer class will affect rowspanKodok
R
22

Based on skube's approach, I found the minimal set of CSS I needed was:

.horizontal-scroll-except-first-column {
  width: 100%;
  overflow: auto;
}

.horizontal-scroll-except-first-column > table {
  margin-left: 8em;
}

.horizontal-scroll-except-first-column > table > * > tr > th:first-child,
.horizontal-scroll-except-first-column > table > * > tr > td:first-child {
  position: absolute;
  width: 8em;
  margin-left: -8em;
  background: #ccc;
}

.horizontal-scroll-except-first-column > table > * > tr > th,
.horizontal-scroll-except-first-column > table > * > tr > td {
  /* Without this, if a cell wraps onto two lines, the first column
   * will look bad, and may need padding. */
  white-space: nowrap;
}
<div class="horizontal-scroll-except-first-column">
  <table>
    <tbody>
      <tr>
        <td>FIXED</td> <td>22222</td> <td>33333</td> <td>44444</td> <td>55555</td> <td>66666</td> <td>77777</td> <td>88888</td> <td>99999</td> <td>AAAAA</td> <td>BBBBB</td> <td>CCCCC</td> <td>DDDDD</td> <td>EEEEE</td> <td>FFFFF</td>
      </tr>
    </tbody>
  </table>
</div>
Rawhide answered 4/11, 2016 at 2:41 Comment(2)
Great and comprehensible, niceToluate
This only works if all the columns in a row are the same height. If the second column has a taller height for example, you can see it when it goes "behind" the first column. Any ideas on how to fix that?Anthrax
W
21

I have a similar table styled like so:

<table style="width:100%; table-layout:fixed">
  <tr>
    <td style="width: 150px">Hello, World!</td>
    <td>
      <div>
        <pre style="margin:0; overflow:scroll">My preformatted content</pre>
      </div>
    </td>
  </tr>
</table>
Winna answered 5/8, 2010 at 15:48 Comment(6)
This answer would really benefit from a demo here.Vulnerary
JSFIDDLE demo so that it's more clear what happens hereBranen
That only scrolls a single cell…Hectogram
I don't know why this is the accepted answer. The question says: and the rest of the table, which in my point of view includes more than one column...Olid
and the columns should be in sync with the headers, like if the columns scroll; headers should scroll too with the columns. But I don't think they both will be in sync after implementing this solutionPrepuce
this is best optionCharlot
U
11

You can use below table style to have horizontal scrolling table with fixed first column.

table,
th,
td {
  border: 1px solid black;
}

.table-style {
  overflow-x: auto;
}

.table-style tr th:first-child {
  position: sticky;
  left: 0;
  z-index: 2;
  background-color: white;
}
<div class="table-style">
  <table>
    <thead>
      <tr>
        <th>_col1_row1_</th>
        <th>_col2_row1_</th>
        <th>_col3_row1_</th>
        <th>_col4_row1_</th>
        <th>_col5_row1_</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th>_col1_row2_</th>
        <td>_col2_row2_</td>
        <td>_col3_row2_</td>
        <td>_col4_row2_</td>
        <td>_col5_row2_</td>
      </tr>
      <tr>
        <th>_col1_row3_</th>
        <td>_col2_row3_</td>
        <td>_col3_row3_</td>
        <td>_col4_row3_</td>
        <td>_col5_row3_</td>
      </tr>
      <tr>
        <th>_col1_row4_</th>
        <td>_col2_row4_</td>
        <td>_col3_row4_</td>
        <td>_col4_row4_</td>
        <td>_col5_row4_</td>
      </tr>
      <tr>
        <th>_col1_row5_</th>
        <td>_col2_row5_</td>
        <td>_col3_row5_</td>
        <td>_col4_row5_</td>
        <td>_col5_row5_</td>
      </tr>
    </tbody>
  </table>
Unscientific answered 1/7, 2021 at 6:30 Comment(0)
E
8

Use jQuery DataTables plug-in, it supports fixed header and columns. This example adds fixed column support to the html table "example":

http://datatables.net/extensions/fixedcolumns/

For two fixed columns:

http://www.datatables.net/release-datatables/extensions/FixedColumns/examples/two_columns.html

Epistaxis answered 13/9, 2011 at 21:48 Comment(1)
Fixing left hand-side columns is done by using the leftColumns initialisation parameter. This link works datatables.net/extensions/fixedcolumns (today)Glutton
N
5

Here's an example with fixed first and last columns. Sticky works better than absolute positioning for expanding the rows when the cells have more content.

Note - this also works with rowspan table cells. The table holds its correct shape.

.wrapper {
  overflow-x:scroll;
  width:100%; 
}
table {
  table-layout: fixed; 
  width: 100%;
  border-collapse: collapse;
  background: white;
}
tr {
  border-top: 1px solid #ccc;
}
td, th {
  vertical-align: top;
  text-align: left;
  width:150px;
  padding: 5px;
}
.fix {
  position:sticky;
  background: white;
}
.fix:first-child {
  left:0;
  width:180px;
}
.fix:last-child {
  right:0;
  width:120px;
}
  <div class="wrapper">
    <table>
      <thead>
        <th class='fix'>Fixed</th>
        <th>Col 1</th>
        <th>Col 2</th>
        <th>Col 3</th>
        <th>Col 4</th>
        <th>Col 5</th>
        <th class='fix'>Fixed</th>
      </thead>
      <tbody>
        <tr>
          <td class='fix'>First Content</td>
          <td>A1</td>
          <td>A2 (with longer content)</td>
          <td>A3</td>
          <td>A4</td>
          <td>A5</td>
          <td class='fix'>Last Content</td>
        </tr>
        <tr>
          <td class='fix'>First Content (with longer content)</td>
          <td>B1</td>
          <td>B2</td>
          <td>B3</td>
          <td>B4</td>
          <td>B5</td>
          <td class='fix'>Last Content</td>
        </tr>
        <tr>
          <td class='fix'>First Content</td>
          <td>C1</td>
          <td>C2</td>
          <td>C3</td>
          <td>C4</td>
          <td>C5</td>
          <td class='fix'>Last Content (with longer content)</td>
        </tr>
      </tbody>
    </table>
  </div>

Example to play with: https://jsbin.com/qawidijigi/edit?html,css,output

Nonscheduled answered 31/5, 2022 at 16:26 Comment(0)
D
3

Take a look at this JQuery plugin:

http://fixedheadertable.com

It adds vertical (fixed header row) or horizontal (fixed first column) scrolling to an existing HTML table. There is a demo you can check for both cases of scrolling.

Darg answered 4/1, 2011 at 15:29 Comment(2)
note: this relies on obsoleted features in jquery and has not been updated since about 1 yearEffluent
@HaykSaakian Looks like that project is being updated again now? Says this year, and jQuery version 1.7 is required.Raama

© 2022 - 2024 — McMap. All rights reserved.