How to display scroll bar onto a html table

487,773

Solution 1

Something like this?

http://jsfiddle.net/TweNm/

The idea is to wrap the <table> in a non-statically positioned <div> which has an overflow:auto CSS property. Then position the elements in the <thead> absolutely.

#table-wrapper {
  position:relative;
}
#table-scroll {
  height:150px;
  overflow:auto;  
  margin-top:20px;
}
#table-wrapper table {
  width:100%;

}
#table-wrapper table * {
  background:yellow;
  color:black;
}
#table-wrapper table thead th .text {
  position:absolute;   
  top:-20px;
  z-index:2;
  height:20px;
  width:35%;
  border:1px solid red;
}
<div id="table-wrapper">
  <div id="table-scroll">
    <table>
        <thead>
            <tr>
                <th><span class="text">A</span></th>
                <th><span class="text">B</span></th>
                <th><span class="text">C</span></th>
            </tr>
        </thead>
        <tbody>
          <tr> <td>1, 0</td> <td>2, 0</td> <td>3, 0</td> </tr>
          <tr> <td>1, 1</td> <td>2, 1</td> <td>3, 1</td> </tr>
          <tr> <td>1, 2</td> <td>2, 2</td> <td>3, 2</td> </tr>
          <tr> <td>1, 3</td> <td>2, 3</td> <td>3, 3</td> </tr>
          <tr> <td>1, 4</td> <td>2, 4</td> <td>3, 4</td> </tr>
          <tr> <td>1, 5</td> <td>2, 5</td> <td>3, 5</td> </tr>
          <tr> <td>1, 6</td> <td>2, 6</td> <td>3, 6</td> </tr>
          <tr> <td>1, 7</td> <td>2, 7</td> <td>3, 7</td> </tr>
          <tr> <td>1, 8</td> <td>2, 8</td> <td>3, 8</td> </tr>
          <tr> <td>1, 9</td> <td>2, 9</td> <td>3, 9</td> </tr>
          <tr> <td>1, 10</td> <td>2, 10</td> <td>3, 10</td> </tr>
          <!-- etc... -->
          <tr> <td>1, 99</td> <td>2, 99</td> <td>3, 99</td> </tr>
        </tbody>
    </table>
  </div>
</div>

Solution 2

You have to insert your <table> into a <div> that it has fixed size, and in <div> style you have to set overflow: scroll.

Update:

The original answer was written 10 years ago. These days there are lots of good UI components for table views and showing in proper ways. So my suggestion is to go for one of these free or paid components to make sure you already support lots of edge cases which is already implemented in these components.

Solution 3

The accepted answer provided a good starting point, but if you resize the frame, change the column widths, or even change the table data, the headers will get messed up in various ways. Every other example I've seen has similar issues, or imposes some serious restrictions on the table's layout.

I think I've finally got all these problems solved, though. It took a lot of CSS, but the final product is about as reliable and easy to use as a normal table.

Here's an example that has all the required features to replicate the table referenced by the OP: jsFiddle

The colors and borders would have to be changed to make it identical to the reference. Information on how to make those kinds of changes is provided in the CSS comments.

Here's the code:

/*the following html and body rule sets are required only if using a % width or height*/
/*html {
width: 100%;
height: 100%;
}*/
body {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0 20px 0 20px;
  text-align: center;
  background: white;
}
.scrollingtable {
  box-sizing: border-box;
  display: inline-block;
  vertical-align: middle;
  overflow: hidden;
  width: auto; /*if you want a fixed width, set it here, else set to auto*/
  min-width: 0/*100%*/; /*if you want a % width, set it here, else set to 0*/
  height: 188px/*100%*/; /*set table height here; can be fixed value or %*/
  min-height: 0/*104px*/; /*if using % height, make this large enough to fit scrollbar arrows + caption + thead*/
  font-family: Verdana, Tahoma, sans-serif;
  font-size: 15px;
  line-height: 20px;
  padding: 20px 0 20px 0; /*need enough padding to make room for caption*/
  text-align: left;
}
.scrollingtable * {box-sizing: border-box;}
.scrollingtable > div {
  position: relative;
  border-top: 1px solid black;
  height: 100%;
  padding-top: 20px; /*this determines column header height*/
}
.scrollingtable > div:before {
  top: 0;
  background: cornflowerblue; /*header row background color*/
}
.scrollingtable > div:before,
.scrollingtable > div > div:after {
  content: "";
  position: absolute;
  z-index: -1;
  width: 100%;
  height: 100%;
  left: 0;
}
.scrollingtable > div > div {
  min-height: 0/*43px*/; /*if using % height, make this large enough to fit scrollbar arrows*/
  max-height: 100%;
  overflow: scroll/*auto*/; /*set to auto if using fixed or % width; else scroll*/
  overflow-x: hidden;
  border: 1px solid black; /*border around table body*/
}
.scrollingtable > div > div:after {background: white;} /*match page background color*/
.scrollingtable > div > div > table {
  width: 100%;
  border-spacing: 0;
  margin-top: -20px; /*inverse of column header height*/
  /*margin-right: 17px;*/ /*uncomment if using % width*/
}
.scrollingtable > div > div > table > caption {
  position: absolute;
  top: -20px; /*inverse of caption height*/
  margin-top: -1px; /*inverse of border-width*/
  width: 100%;
  font-weight: bold;
  text-align: center;
}
.scrollingtable > div > div > table > * > tr > * {padding: 0;}
.scrollingtable > div > div > table > thead {
  vertical-align: bottom;
  white-space: nowrap;
  text-align: center;
}
.scrollingtable > div > div > table > thead > tr > * > div {
  display: inline-block;
  padding: 0 6px 0 6px; /*header cell padding*/
}
.scrollingtable > div > div > table > thead > tr > :first-child:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: 20px; /*match column header height*/
  border-left: 1px solid black; /*leftmost header border*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div > div:first-child,
.scrollingtable > div > div > table > thead > tr > * + :before {
  position: absolute;
  top: 0;
  white-space: pre-wrap;
  color: white; /*header row font color*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div[label]:after {content: attr(label);}
.scrollingtable > div > div > table > thead > tr > * + :before {
  content: "";
  display: block;
  min-height: 20px; /*match column header height*/
  padding-top: 1px;
  border-left: 1px solid black; /*borders between header cells*/
}
.scrollingtable .scrollbarhead {float: right;}
.scrollingtable .scrollbarhead:before {
  position: absolute;
  width: 100px;
  top: -1px; /*inverse border-width*/
  background: white; /*match page background color*/
}
.scrollingtable > div > div > table > tbody > tr:after {
  content: "";
  display: table-cell;
  position: relative;
  padding: 0;
  border-top: 1px solid black;
  top: -1px; /*inverse of border width*/
}
.scrollingtable > div > div > table > tbody {vertical-align: top;}
.scrollingtable > div > div > table > tbody > tr {background: white;}
.scrollingtable > div > div > table > tbody > tr > * {
  border-bottom: 1px solid black;
  padding: 0 6px 0 6px;
  height: 20px; /*match column header height*/
}
.scrollingtable > div > div > table > tbody:last-of-type > tr:last-child > * {border-bottom: none;}
.scrollingtable > div > div > table > tbody > tr:nth-child(even) {background: gainsboro;} /*alternate row color*/
.scrollingtable > div > div > table > tbody > tr > * + * {border-left: 1px solid black;} /*borders between body cells*/
<div class="scrollingtable">
  <div>
    <div>
      <table>
        <caption>Top Caption</caption>
        <thead>
          <tr>
            <th><div label="Column 1"></div></th>
            <th><div label="Column 2"></div></th>
            <th><div label="Column 3"></div></th>
            <th>
              <!--more versatile way of doing column label; requires 2 identical copies of label-->
              <div><div>Column 4</div><div>Column 4</div></div>
            </th>
            <th class="scrollbarhead"/> <!--ALWAYS ADD THIS EXTRA CELL AT END OF HEADER ROW-->
          </tr>
        </thead>
        <tbody>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
        </tbody>
      </table>
    </div>
    Faux bottom caption
  </div>
</div>

<!--[if lte IE 9]><style>.scrollingtable > div > div > table {margin-right: 17px;}</style><![endif]-->

Solution 4

Not sure why no one mentioned to just use the built-in sticky header style for elements. Worked great for me.

.tableContainerDiv {
   overflow: auto;
   max-height: 80em;
}
th {
   position: sticky;
   top: 0;
   background: white;
}

Put a min-width on the in @media if you need to make responsive (or similar).

see Table headers position:sticky or Position Sticky and Table Headers

Solution 5

I resolved this problem by separating my content into two tables.

One table is the header row.

The seconds is also <table> tag, but wrapped by <div> with static height and overflow scroll.

Share:
487,773

Related videos on Youtube

BruceyBandit
Author by

BruceyBandit

I am currently a Master Student, Database programming is my strength but in my current project I have to not only use MYSQL but also Javascript, Jqueries, PHP, HTML and CSS. My dream is to get a PHD so that I get the title of doctor and really make my parents proud.

Updated on April 23, 2021

Comments

  • BruceyBandit
    BruceyBandit about 3 years

    I am writing a page where I need an html table to maintain a set size. I need the headers at the top of the table to stay there at all times but I also need the body of the table to scroll no matter how many rows are added to the table.

    I want it to look like method 2 in this url: http://www.cssplay.co.uk/menu/tablescroll.html

    I have tried doing this but no scrollbar appears:

    tbody {
      height: 80em;
      overflow: scroll;
    }
    <table border=1 id="qandatbl" align="center">
      <tr>
        <th class="col1">Question No</th>
        <th class="col2">Option Type</th>
        <th class="col1">Duration</th>
      </tr>
    
      <tbody>
        <tr>
          <td class='qid'></td>
          <td class="options"></td>
          <td class="duration"></td>
        </tr>
      </tbody>
    </table>
    • Mike Park
      Mike Park over 12 years
      Why don't you use the code from the example method? You can't use <tbody> unfortunately.
  • Fractaliste
    Fractaliste almost 10 years
    How about no width-fixed columns?
  • Antonio
    Antonio over 8 years
    I tried your answer but header columns are not aligned. I used only your css in a style tag inside the body tag where I copied your table
  • Ziggler
    Ziggler over 7 years
    gave height as 500px for my div and it worked fine. <div style="overflow:scroll; height:500px;">
  • nanker
    nanker over 7 years
    awesome job. I have a table with 15 columns, however, and I can't seem to contain the table to the page without a horizontal scrollbar now too. I've tried tweaking your css, your beautifully coded css, to accomodate more dynamic width'd columns but nothing I change other than table width makes a difference. If I change table width to 100%, then the table renders in the width of the table, but because the column widths won't wrap I still can not see all 15 columns of data. I almost have a scrolling table that looks way-kewl, so any help appreciated.
  • nanker
    nanker over 7 years
    oh wait a sec, no horizontal scrollbar, the table just cuts off.
  • DoctorDestructo
    DoctorDestructo over 7 years
    @nanker If you need horizontal scrolling and are willing to use a tiny bit of JavaScript, you should check this answer. It's the best way to do a scrolling table that I'm aware of. There was no good way to do horizontal scrolling with just CSS back when I posted this answer, but I haven't looked into it for a while so I don't know what's possible now.
  • David I. McIntosh
    David I. McIntosh about 7 years
    Awesome work. Could you comment on how to tweak for multiple header rows? Simply repeating the <tr><th></th>..</tr> construct clearly does not work. Thanks.
  • DoctorDestructo
    DoctorDestructo about 7 years
    @DavidI.McIntosh A multi-row header would be tricky using this technique. Adding rows would be easy, but I'm not sure how you'd get the horizontal borders between them. You might want to try the JavaScript solution I linked in my previous comment unless you can't use JS for some reason.
  • Daniil Shevelev
    Daniil Shevelev about 6 years
    Great solution, but I am having problems with it. When try to hide a row and set display:none there are some white spaces between rows. That is not the case with the regular table. Any ideas, tips or suggestions?
  • amallard
    amallard about 6 years
    Don't know why everyone made it so complicated. This should be the accepted answer.
  • lsimonetti
    lsimonetti about 6 years
    This is by far the easiest solution. There may be caveats to adding a div with an overflow and fixed height but this solution will at least set you in the right direction.
  • TylerH
    TylerH over 5 years
    This is the same implementation as Zvi's answer a year prior.
  • Sandepku
    Sandepku over 4 years
    Superb answer mate! Cheers to you :)-
  • Sora.
    Sora. almost 4 years
    @Antonio: I had the same problem (centered* header columns seeming non-aligned), but adding transform: translateX(-50%) did the trick for me [*centered being the standard styling in Firefox which is removed by the „normalize CSS“ option in this answer's JSFiddle]
  • I try so hard but I cry harder
    I try so hard but I cry harder over 3 years
    This should be the accepted answer. Simple, straight to the point and I do not destroy anything else with it.
  • Guest
    Guest over 3 years
    Okay, I will add it in the next answer.
  • Guest
    Guest over 3 years
    Okay, did it, I don't yet know how to indent code properly yet on stack overflow.
  • giraffedata
    giraffedata over 3 years
    The question was how to make a table body scroll vertically while the column header stays put.
  • richnis
    richnis about 3 years
    I believe that this solution won't work because the header of the table will disappear if the table is scrolled too far. This does not satisfy the requirements of the original post, which says to keep the headers in place at all times.
  • Hossein
    Hossein about 3 years
    @richnis, the answer need to update, I update that.
  • William Walseth
    William Walseth about 3 years
    This is a cleaner, approach, closer to original tables, with a minimal amount of css. The other answers are outdated.