80

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?

C R
  • 2,182
  • 5
  • 32
  • 41
Alan
  • 2,109
  • 5
  • 25
  • 28
  • 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? – Rimas Kudelis Sep 04 '10 at 11:09
  • See my answer on similar question: http://stackoverflow.com/a/17557830/1763149 – Marcin Raczyński Jul 09 '13 at 20:49

7 Answers7

125

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

w00t
  • 17,944
  • 8
  • 54
  • 62
skube
  • 5,867
  • 9
  • 53
  • 77
  • Simple but effective solution to my query! – Jimbo Jones Mar 06 '13 at 15:21
  • 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 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.
    – Kras Aug 01 '13 at 19:21
  • 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: http://jsbin.com/sesurutojo/edit?output – Justin Aug 23 '15 at 01:42
  • 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? – Megha kaur Dec 08 '15 at 15:04
  • 2
    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. – Bruce May 23 '16 at 00:00
  • @skube : how to set height for the based on content in fixed column – Yogesh Jun 17 '16 at 18:56
  • @blahdiblah :how to set height for the based on content in fixed column – Yogesh Jun 17 '16 at 18:56
  • what about if there is paging? – Jigar7521 Jan 03 '17 at 05:54
  • @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. – w00t Jan 11 '17 at 15:42
  • @w00t 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 rowspan – lisa_rao007 Apr 06 '17 at 19:36
21

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>
joeytwiddle
  • 29,306
  • 13
  • 121
  • 110
19

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>
Nexo
  • 2,125
  • 2
  • 10
  • 20
kbrimington
  • 25,142
  • 5
  • 62
  • 74
8

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>
Nexo
  • 2,125
  • 2
  • 10
  • 20
Prashant
  • 121
  • 1
  • 3
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

Martin
  • 2,135
  • 8
  • 39
  • 42
mas_oz2k1
  • 2,851
  • 3
  • 34
  • 41
  • Fixing left hand-side columns is done by using the leftColumns initialisation parameter. This link works http://www.datatables.net/extensions/fixedcolumns/ (today) – jpkeisala May 16 '15 at 08:23
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.

Rahat Ahmed
  • 2,191
  • 2
  • 30
  • 40
Markos Fragkakis
  • 7,499
  • 18
  • 65
  • 103
3

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

Mark Swardstrom
  • 17,217
  • 6
  • 62
  • 70