Make TBODY scrollable in Webkit browsers

HtmlCssWebkit

Html Problem Overview


I'm aware of this question, but none of the answers work in Safari, Chrome, etc.

The accepted strategy (as demonstrated here) is to set the tbody height and overflow properties like so:

<table>
    <thead>
        <tr><th>This is the header and doesn't scroll</th></tr>
    </thead>
    <tbody style="height:100px; overflow:auto;">
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
    </tbody>
</table>

Unfortunately, this does not work in any webkit browsers. There is a bug report about it that doesn't seem to be a high priority (reported June 05).

So my question is: are there alternate strategies that do actually work? I've tried the two-table approach, but it's impossible to guarantee that the header will line up with the content. Do I just have to wait for Webkit to fix it?

Html Solutions


Solution 1 - Html

Here is a working example:

http://www.imaputz.com/cssStuff/bigFourVersion.html

You have to add the display:block to the thead > tr and tbody

Solution 2 - Html

Using the display:block style only works if you have 1 column. If you have multiple data columns - with multiple fields - then display:block appears to make all data columns scrollable but under the 1st column (does the same in Firefox - which is the only browser I know that does tbody scrolling nicely). Incidentally, on Firefox - you can use the overflow-x: hidden style to suppress the horizontal scroll.

I realized that the issue I mention only occurs if you are not specifying a width for the th & td elements - if you can fix the column widths then it works. Problem for me is I can't fix the column widths.

Solution 3 - Html

Try the first method of this page, pure CSS with a single table (2 divs around the table, and the thead is positionned absolute) : http://www.cssplay.co.uk/menu/tablescroll.html Seems to work on FF4/IE9/IE8 in addition to IE7/FF3.6.

Solution 4 - Html

I had the same issue and wrote a jQuery script to do this for me... uses two table elements and formats the css accordingly. Hope this helps others who have the same issue...

http://jsfiddle.net/pe295/1/

Solution 5 - Html

I saw Sean Haddy's excellent solution and took the liberty of making some edits:

  • Use classes instead of ID, so one jQuery script could be reused for multiple tables on one page
  • Added support for semantic HTML table elements like caption, thead, tfoot, and tbody
  • Made scrollbar optional so it won't appear for tables that are "shorter" than the scrollable height
  • Adjusted scrolling div's width to bring the scrollbar up to the right edge of the table
  • Made concept accessible by
    • using aria-hidden="true" on injected static table header
    • and leaving original thead in place, just hidden with jQuery and set aria-hidden="false"
  • Showed examples of multiple tables with different sizes

Sean did the heavy lifting, though. Thanks to Matt Burland, too, for pointing out need to support tfoot.

Please see for yourself at http://jsfiddle.net/jhfrench/eNP2N/

Solution 6 - Html

A faced the same problem long ago, and I finally set out the two tables approach. This is the result: http://jsfiddle.net/bGr4V/3/, it works for all browsers (IE6+ incl).

In this jsFiddle you can play with a clean version.

My solution was to add a fix cell <th class="fix"> </th> in thead to fill the space of the scroll bar in the tbody, then give one column a variable width (<td class="grow">), so the header fix cell wouldn't unmatch on resizing.

HTML:

<div class="fixed_table">
  <div class="head">
    <table>
      <thead>
        <tr>
          <th>Column header</th>
          <th class="grow">Column header</th>
          <th class="fix"> </th>
        </tr>
      </thead>
    </table>
  <div class="body">
    <table class="full_table">
      <caption class="caption">Caption</caption>
      <tbody>
        <tr>
          <td>Data</td>
          <td class="grow">Data</td>
        </tr>
        <tr>
          <td>...</td>
          <td>...</td>
        </tr>
        <tr>
          <td>...</td>
          <td>...</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

CSS: has * and _ hack for ie6-7, and a -webkit specific for the header fix-cell matching scroll width in each case.

.fixed_table table {
  table-layout: fixed;
  width: auto;
  border-width: 0;
  padding: 0;
  border-collapse: collapse;
}

.fixed_table .body {
  overflow: scroll;
  overflow-x: hidden;
  max-height: 10.75em;
  min-height: 2.5em;
  padding-bottom: 0.8em;
  *padding-right: 17px; /*ie7 & ie6*/
  _padding-right: 0; /*ie6*/
  _height: 10em ;
}

.fixed_table th, .fixed_table td {
  width: 4.7em;
}

.fixed_table .grow {
  width: auto;
}

.fixed_table .fix {
  width: 16px;
  *width: 17px; /*ie7 & ie6*/
  _width: 16px; /*ie6*/
}

/* webkit specific */
@media screen and (-webkit-min-device-pixel-ratio:0) {
  .fixed_table .fix{ width: 17px }
}

Solution 7 - Html

Thought I'd throw my solution into the mix - http://tjvantoll.com/2012/11/10/creating-cross-browser-scrollable-tbody/.

It takes the same basic route as @Michael Koper's solution but includes a workaround so the table will look correct in IE back to IE6.

I solve the width issue by giving the <table> a table-layout: fixed and explicitly assigning width to cells in each column. Not ideal but it does produce a semantic table that will align cross browser regardless of whether a scrollbar is needed.

Demo: http://codepen.io/tjvantoll/pen/JEKIu

Solution 8 - Html

I developed javascript solution for the above problem
which works only in Firefox 7+ as i have tested only in FF

I came to this thread and found solution pointed by Michael Koper

In this solution three important things are done

  1. fix the column width
  2. thead > tr display is set to block
  3. tbody display is set to block

as others have mentioned there problem to fix the width , i am also in same position;
even i cant fix the width statically

so i thought i will fix the width dynamically ( after table is rendered in browser) and this did the trick :)

following is the solution in javascript which works only in FF
( i have tested only in FF , i dont have access to other browsers )

       function test1(){                
            var tbodys = document.getElementsByTagName("TBODY");
            for(var i=0;i<tbodys.length;i++){
                do_tbodyscroll(tbodys[i]);
            }
        }


      function do_tbodyscroll(_tbody){
            // get the table node 
            var table = _tbody.parentNode;
            
            // first row of tbody 
            var _fr = _tbody.getElementsByTagName("TR")[0];
            
            // first row cells .. 
            var _frcells = _fr.cells;
            
            // Width array , width of each element is stored in this array 
            var widtharray = new Array(_frcells.length);
            
            for(var i=0;i<_frcells.length;i++){                    
                widtharray[i] = _frcells[i].scrollWidth;
            }                
            
            // Apply width to first row                  
            for(var i=0;i<_frcells.length;i++){
                _frcells[i].width = widtharray[i];                   
            }                 
             
            // Get the Last row in Thead ... 
            // COLGROUPS USING COLSPAN NOT YET SUPPORTED
             
            var thead = table.getElementsByTagName("THEAD")[0];
            var _rows = thead.getElementsByTagName("TR");
            var tableheader = _rows[_rows.length - 1];
            var headercells = tableheader.cells;
            
            // Apply width to header ..                                
            for(var i=0;i<headercells.length;i++){
                headercells[i].width = widtharray[i];
            }
            
            // ADD 16 Pixel of scroll bar to last column ..
            headercells[headercells.length -1 ].width = widtharray[headercells.length -1] + 16;
            
            tableheader.style.display = "block";
            _tbody.style.display = "block";  
        }

This solutions finds out what is the width of column from browser
and set again the same width to columns ( header and first row of tbody )
after the width is set; thead > tr and tbody display is set to block

Hope this solution is useful for all of you ..
if you can extend it to other browsers please reply to this post

Solution 9 - Html

This is really quite hacky but maybe it will help someone somewhere...

http://jsfiddle.net/yUHCq/1/

It uses columns instead of rows so processing it would essentially be done backwards.

Transitional DOCTYPE added for IE compatibility.

Solution 10 - Html

It may be overkill for this question, but YUI still provides possibly the best free cross-browser datatable. It can be used for read-only data as well.

YUI 2 DataTable

YUI 3 DataTable

Click on the examples there to see scrollable samples. Since, I am a newbie to stackoverflow, I can only post these two links.

Solution 11 - Html

Add display:block; This will also remove the unnecessary horizontal scroll in FireFox as well. You are also, no doubt, aware that neither example works in MSIE 8.

<table>
    <thead>
        <tr><th>This is the header and doesn't scroll</th></tr>
    </thead>
    <tbody style="height:100px; overflow:auto;display:block;">
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
    </tbody>
</table>

Solution 12 - Html

There is an example here that works in IE5+, Firefox and Chrome. However, it uses fixed width columns. http://www.cssplay.co.uk/menu/tablescroll.html

Solution 13 - Html

If anyone needs it to work in IE quirks mode, here is how I changed and simplified I.G. Pascual's code to work:

.fixed_table{
       overflow: scroll;
       overflow-x: hidden;
       max-height: 300px;
       height: 300px;
       min-height: 50px;
       padding-right:0;
}
#datatable td 
{
       padding:3px;
       text-align: center;
       width: 9%;
       vertical-align: middle;
       background-color: #343435; 
       color: #E0E0E3;
       overflow:hidden;
} 
<div class="head">
    <table>
        <thead>
            <tr>
                <th>Time (GMT)</th>
                <th>Price</th>
            </tr>
        </thead>
    </table>
</div>
<div class="fixed_table">
    <table id="datatable" cellspacing="1" cellpadding="1">
        <tbody></tbody>
    </table>
</div>

Solution 14 - Html

Let the table draw as it's way and calculate each column's width and set it in to each heading. Headings are made with divisions and then we can let the table to be scrolled free.

<!DOCTYPE html>
<html>
<head>
<style>
.t_heading{
  margin-top: 20px;
  font-family: Verdana, Geneva, sans-serif;
  background-color: #4CAF50;
}

.heading{
  background-color: #4CAF50;
  color: white;
  float:left;
  padding: 8px 0PX 8PX 0PX;
  border-bottom: 1px solid #ddd;
  height: 20px;
  text-align: left;
}

.t_data{
  overflow-y: scroll;
  overflow-x: hidden;
  height:0px;
  width: 100%;

}

.t_content{
	border-collapse: collapse;
    font-family: Verdana, Geneva, sans-serif;
    width: 100%;
}

.column1,.column2,.column3,.column4{
	padding: 8px 0PX 8PX 0PX;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
.t_row:hover{
  background-color:#f5f5f5;
}
</style>
<script>
function setBody(){
	var body = document.body,
    html = document.documentElement;

	var height = Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );
	height = height-300;
	/*
	 ** By changing the subtraction value, You can fit the table in to the screen correctly.
	 ** Make sure not to come the hscroll.
	 ** Or you can set fixed height with css for the div as your wish.
	 */
	document.getElementById("t_data").style.height = height+"px";

	setColumnWidth("column1");
	setColumnWidth("column2");
	setColumnWidth("column3");
	setColumnWidth("column4");
}

function setColumnWidth(o){
		var object = o;
		var x = document.getElementsByClassName(object);
    	var y = x[0].clientWidth;
    	document.getElementById(object).style.width = y+"px";
 }
</script>
</head>

<body onload="setBody()">
<div class="t_heading">
<div class="heading"  id="column1">Heading 1</div>
<div class="heading"  id="column2">Heading 2</div>
<div class="heading"  id="column3">Heading 3</div>
<div class="heading"  id="column4">Heading 4</div>
</div>
<div class="t_data" id="t_data">
<table class="t_content">
	<tr class='t_row'>
		<td class='column1'>Column1 Row 0</td>
		<td class='column2'>Column2 Row 0</td>
		<td class='column3'>Column3 Row 0</td>
		<td class='column4'>Column4 Row 0</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 1</td>
		<td class='column2'>Column2 Row 1</td>
		<td class='column3'>Column3 Row 1</td>
		<td class='column4'>Column4 Row 1</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 2</td>
		<td class='column2'>Column2 Row 2</td>
		<td class='column3'>Column3 Row 2</td>
		<td class='column4'>Column4 Row 2</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 3</td>
		<td class='column2'>Column2 Row 3</td>
		<td class='column3'>Column3 Row 3</td>
		<td class='column4'>Column4 Row 3</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 4</td>
		<td class='column2'>Column2 Row 4</td>
		<td class='column3'>Column3 Row 4</td>
		<td class='column4'>Column4 Row 4</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 5</td>
		<td class='column2'>Column2 Row 5</td>
		<td class='column3'>Column3 Row 5</td>
		<td class='column4'>Column4 Row 5</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 6</td>
		<td class='column2'>Column2 Row 6</td>
		<td class='column3'>Column3 Row 6</td>
		<td class='column4'>Column4 Row 6</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 7</td>
		<td class='column2'>Column2 Row 7</td>
		<td class='column3'>Column3 Row 7</td>
		<td class='column4'>Column4 Row 7</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 8</td>
		<td class='column2'>Column2 Row 8</td>
		<td class='column3'>Column3 Row 8</td>
		<td class='column4'>Column4 Row 8</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 9</td>
		<td class='column2'>Column2 Row 9</td>
		<td class='column3'>Column3 Row 9</td>
		<td class='column4'>Column4 Row 9</td>
	</tr><tr class='t_row'>
		<td class='column1'>Column1 Row 10</td>
		<td class='column2'>Column2 Row 10</td>
		<td class='column3'>Column3 Row 10</td>
		<td class='column4'>Column4 Row 10</td>
	</tr>
<!--
<?php
$data = array();
for($a = 0; $a<50; $a++)
{
	$data[$a] = array();
	$data[$a][0] = "Column1 Row ".$a;
	$data[$a][1] = "Column2 Row ".$a;
	$data[$a][2] = "Column3 Row ".$a;
	$data[$a][3] = "Column4 Row ".$a;
}
/*
 ** supose you have data in an array.. which red from database. The table will draw using array data. Or you can draw the table manualy.
 ** tip: If using manual table, No need of
 ** 'var x = document.getElementsByClassName(object); var y = x[0].clientWidth;'.
 ** You can just set ID of first row's cells in to some name and use it to read width.
 */
for($i=0;$i<sizeof($data);$i++){
	echo "<tr class='t_row'><td class='column1'>".$data[$i][0]."</td><td class='column2'>".$data[$i][1]."</td><td class='column3'>".$data[$i][2]."</td><td class='column4'>".$data[$i][3]."</td></tr>";
}
?>
-->
</table>
</div>
</body>
</html>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndrew EnsleyView Question on Stackoverflow
Solution 1 - HtmlMichael KoperView Answer on Stackoverflow
Solution 2 - HtmlMartinView Answer on Stackoverflow
Solution 3 - HtmllsfView Answer on Stackoverflow
Solution 4 - HtmlSean HaddyView Answer on Stackoverflow
Solution 5 - HtmlJeromy FrenchView Answer on Stackoverflow
Solution 6 - HtmlI.G. PascualView Answer on Stackoverflow
Solution 7 - HtmlTJ VanTollView Answer on Stackoverflow
Solution 8 - HtmlDigambar SangavkarView Answer on Stackoverflow
Solution 9 - HtmlMatthewView Answer on Stackoverflow
Solution 10 - Htmluser2030366View Answer on Stackoverflow
Solution 11 - HtmlmmcglynnView Answer on Stackoverflow
Solution 12 - Htmluser1491819View Answer on Stackoverflow
Solution 13 - HtmlRonen FestingerView Answer on Stackoverflow
Solution 14 - HtmlSalitha PrasadView Answer on Stackoverflow