16

enter image description hereI need your help. I am unsure as to how to freeze or have the top row of my table, which contains the headers to remain frozen, while I would be able to scroll through the table? Using only CSS markup and NO Javascript frameworks, how would I be able to accomplish this?

<!DOCTYPE html>
<html>
<head>

<style type="text/css">

/*------------------------------------------------------------------
Table Style
------------------------------------------------------------------ */
table a:link {
    color: #666;
    font-weight: bold;
    text-decoration:none;
}
table a:visited {
    color: #999999;
    font-weight:bold;
    text-decoration:none;
}
table a:active,
table a:hover {
    color: #bd5a35;
    text-decoration:underline;
}
table {
    font-family:Arial, Helvetica, sans-serif;
    color:#666;
    font-size:12px;
    background:#eaebec;
    border:#ccc 1px solid;

    border-radius:3px;
    border-collapse:collapse; border-spacing: 0; 

    box-shadow: 0 1px 2px #d1d1d1;
    min-width: 1000px;
}
table th {
    padding:10px 10px 10px 10px;
    border-top:0;
    border-bottom:1px solid #e0e0e0;
    border-left: 1px solid #e0e0e0;

    background: #ededed;
}
table th:first-child {
    text-align: left;
}
table tr:first-child th:first-child {
    border-top-left-radius:3px;
    border-left: 0;
}
table tr:first-child th:last-child {
    border-top-right-radius:3px;
}
table tr {
    text-align: center;
}
table td:first-child {
    text-align: left;
    border-left: 0;
}
table td {
    padding:10px;
    border-bottom:1px solid #e0e0e0;
    border-left: 1px solid #e0e0e0;
    background: #fafafa;
}
table tr:last-child td {
    border-bottom:0;
}
table tr:last-child td:first-child {
    border-bottom-left-radius:3px;
}
table tr:last-child td:last-child {
    border-bottom-right-radius:3px;
}
table tr:hover td {
    background: #f2f2f2;

}
table th, table td {
    width: 160px;

}
#wrapper {
    width: 740px;
    height: 200px;
    overflow-x: scroll;
    overflow-y: scroll;
}
table thead {
    position: fixed;
}
</style>

</head>

<body>

<div id="wrapper">
<table>

    <!-- Table Header -->
    <thead>
        <tr>
            <th>Task Details</th>
            <th>Firstname</th>
            <th>Lastname</th>
            <th>Progress</th>
            <th>Vital Task</th>
        </tr>
    </thead>
    <!-- Table Header -->

    <!-- Table Body -->
    <tbody>

        <tr>
            <td>Create pretty table design</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>100%</td>
            <td>Yes</td>
        </tr><!-- Table Row -->

        <tr>
            <td>Take the dog for a walk</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>100%</td>
            <td>Yes</td>
        </tr><!-- Darker Table Row -->

        <tr>
            <td>Waste half the day on Twitter</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>20%</td>
            <td>No</td>
        </tr>

        <tr>
            <td>Feel inferior after viewing Dribble</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>80%</td>
            <td>No</td>
        </tr>

        <tr>
            <td>Wince at &quot;to do&quot; list</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>100%</td>
            <td>Yes</td>
        </tr>

        <tr>
            <td>Vow to complete personal project</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>23%</td>
            <td>yes</td>
        </tr>

        <tr>
            <td>Procrastinate</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>80%</td>
            <td>No</td>
        </tr>

        <tr>
            <td><a href="#yep-iit-doesnt-exist">Hyperlink Example</a></td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>80%</td>
            <td><a href="#inexistent-id">Another</a></td>
        </tr>

    </tbody>
    <!-- Table Body -->

</table>
</div>

</body>
</html>
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
John Smith
  • 1,639
  • 11
  • 36
  • 51
  • Possible duplicate of [Freeze the top row for an html table only (Fixed Table Header Scrolling)](https://stackoverflow.com/questions/8423768/freeze-the-top-row-for-an-html-table-only-fixed-table-header-scrolling) – Mohamad Hamouday Aug 24 '18 at 09:42

3 Answers3

10

Add below to css.

table thead {
  position: fixed;
}

Try this code

<!DOCTYPE html>
<html>
<head>

<style type="text/css">

/*------------------------------------------------------------------
Table Style
------------------------------------------------------------------ */
table a:link {
    color: #666;
    font-weight: bold;
    text-decoration:none;
}
table a:visited {
    color: #999999;
    font-weight:bold;
    text-decoration:none;
}
table a:active,
table a:hover {
    color: #bd5a35;
    text-decoration:underline;
}
table {
    font-family:Arial, Helvetica, sans-serif;
    color:#666;
    font-size:12px;
    background:#eaebec;
    border:#ccc 1px solid;

    border-radius:3px;
    border-collapse:collapse; border-spacing: 0; 

    box-shadow: 0 1px 2px #d1d1d1;
}
table th {
    padding:10px 10px 10px 10px;
    border-top:0;
    border-bottom:1px solid #e0e0e0;
    border-left: 1px solid #e0e0e0;

    background: #ededed;
}
table th:first-child {
    text-align: left;
}
table tr:first-child th:first-child {
    border-top-left-radius:3px;
    border-left: 0;
}
table tr:first-child th:last-child {
    border-top-right-radius:3px;
}
table tr {
    text-align: center;
}
table td:first-child {
    text-align: left;
    border-left: 0;
}
table td {
    padding:10px;
    border-bottom:1px solid #e0e0e0;
    border-left: 1px solid #e0e0e0;
    background: #fafafa;
}
table tr:last-child td {
    border-bottom:0;
}
table tr:last-child td:first-child {
    border-bottom-left-radius:3px;
}
table tr:last-child td:last-child {
    border-bottom-right-radius:3px;
}
table tr:hover td {
    background: #f2f2f2;

}
table th, table td {
    width: 160px;

}
#wrapper {
    width: 740px;
    height: 300px;
    overflow-x: scroll;
    overflow-y: scroll;
}
table thead
{
    position:fixed;
}
</style>

</head>

<body>

<div id="wrapper">
<table>

    <!-- Table Header -->
    <thead>
        <tr>
            <th>Task Details</th>
            <th>Firstname</th>
            <th>Progress</th>
            <th>Vital Task</th>
        </tr>
    </thead>
    <!-- Table Header -->

    <!-- Table Body -->
    <tbody>

        <tr>
            <td>Create pretty table design</td>
            <td>&nbsp;</td>
            <td>100%</td>
            <td>Yes</td>
        </tr><!-- Table Row -->

        <tr>
            <td>Take the dog for a walk</td>
            <td>&nbsp;</td>
            <td>100%</td>
            <td>Yes</td>
        </tr><!-- Darker Table Row -->

        <tr>
            <td>Waste half the day on Twitter</td>
            <td>&nbsp;</td>
            <td>20%</td>
            <td>No</td>
        </tr>

        <tr>
            <td>Feel inferior after viewing Dribble</td>
            <td>&nbsp;</td>
            <td>80%</td>
            <td>No</td>
        </tr>

        <tr>
            <td>Wince at &quot;to do&quot; list</td>
            <td>&nbsp;</td>
            <td>100%</td>
            <td>Yes</td>
        </tr>

        <tr>
            <td>Vow to complete personal project</td>
            <td>&nbsp;</td>
            <td>23%</td>
            <td>yes</td>
        </tr>

        <tr>
            <td>Procrastinate</td>
            <td>&nbsp;</td>
            <td>80%</td>
            <td>No</td>
        </tr>

        <tr>
            <td><a href="#yep-iit-doesnt-exist">Hyperlink Example</a></td>
            <td>&nbsp;</td>
            <td>80%</td>
            <td><a href="#inexistent-id">Another</a></td>
        </tr>

    </tbody>
    <!-- Table Body -->

</table>
</div>

</body>
</html>
Dipesh Parmar
  • 27,090
  • 8
  • 61
  • 90
  • this works, but it mangles the columns by expanding them past the table itself. Anyway to clean this up? (See pic on top) – John Smith Mar 09 '13 at 04:37
  • @JohnSmith if you don't mind can you paste new code because i already tested it and its working as expected.. – Dipesh Parmar Mar 09 '13 at 04:42
  • @JohnSmith i have updated my answer try that code...you have css for table th and table tr and set width manually that was causing problem. – Dipesh Parmar Mar 09 '13 at 04:52
  • 2
    One problem with this solution is the first row is always hidden - tested in Chrome 32.0.1700.77 and Firefox 26. Otherwise, it works great! – Dan Morphis Feb 22 '14 at 00:40
  • 1
    This does not work with a lot of columns as well. Here is the link http://jsfiddle.net/eaYVA/ – Ravi Feb 24 '14 at 17:24
  • @DanMorphis I also got same problem with this solution. Did u solved this issue? If so then please share with me. – Programmer Feb 01 '15 at 06:32
  • @Programmer I did not. I ended up going a different route and used jqGrid – Dan Morphis Feb 02 '15 at 18:15
  • @DanMorphis Can you please share your solution? It willl be a great help.Thanks! – Programmer Feb 03 '15 at 05:23
  • Here is the fiddle if anyone is interested: http://jsfiddle.net/rcfx58of/. Question: Is there anyway for the "up" arrow to not get overlapped by the header? Also what if there is no tbody or head, like in this example: How about something like this: jsfiddle.net/n1fg39f7. Thanks – SearchForKnowledge Feb 05 '15 at 13:44
  • This code still hides the top row in modern browsers :( – Stephen Jul 15 '16 at 13:12
10

I have a pure CSS scrolling table design that's a bit more refined than most of the others I've seen. It has a simple, polished appearance and renders perfectly in the popular desktop browsers, including Internet Explorer back to version 8. One of its nicer features is the option to let the content determine the width of the table and columns instead of setting them to predetermined values. That's the default behavior for tables, but I've seen a lot of CSS scrolling tables that require fixed or percent widths on the columns, the table, or both.

Here are some fiddles you can check out:

  • Fluid Width and Height (adapts to screen size): jsFiddle (Note that the scrollbar only shows up when needed in this configuration, so you may have to shrink the frame to see it)

  • Auto Width, Fixed Height (easier to integrate with other content): jsFiddle

The second one is probably useful in more situations, so I'll post the code for it below...

/*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>
              <!--Here's a more versatile way of doing a column label; unlike the
              custom label attribute used above, it's fully stylable, but requires 2
              identical copies of the label-->
              <div><div>Column 4</div><div>Column 4</div></div>
            </th>
            <th class="scrollbarhead"></th> <!--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]-->
DoctorDestructo
  • 4,166
  • 25
  • 43
  • This is great and all but from what I'm seeing the column header stuff is not working. I'm getting intellisense errors from your css. Perhaps this is just a bit out-dated? – Methodician Jun 24 '16 at 22:14
  • @Methodician It's only outdated if someone has come up with something better (which is entirely possible). If you're copying the CSS snippet directly into a CSS file, be sure to get rid of the style tags and conditional comment, since neither of those are valid CSS. – DoctorDestructo Jun 24 '16 at 23:06
1

Add a class in the thead section of the table:

<thead class="stuckHead">
    <tr>
        <!-- ... -->
    </tr>
</thead>

And then in the CSS, add this:

.stuckHead {
    position: sticky;
    top: 0; 
}

Note: Tested on dynamic tables.

carla
  • 141
  • 9