<!DOCTYPE html>
<body>
<head>
<style>
.TableLarge td, .TableLarge th{
border-style: solid;
border-width: 1px;
border-color: #CAE3EF;
padding: 7px;
white-space: nowrap;
font-family: Verdana;
font-size: 10px;
}
.TableLarge{
border-style: none;
border-collapse: collapse;
}
#padding_for_test{
height: 3000px;
width: 9000px;
}
</style>
<script type="text/javascript">
function table_make_fixed_header(elTable, bHorizontal, bVertical, nRepositionIntervalMilliseconds, bWrappedByScrollableDiv)
{
if(!bHorizontal && !bVertical)
return;
if(!elTable.id)
elTable
.id
="FixedVH_Headers_"+(new Date().getTime
())+Math
.floor(Math
.random
()*10000000
);
var zIndex=1;
if(window.getComputedStyle)
zIndex=parseInt(window.getComputedStyle(elTable))?parseInt(window.getComputedStyle(elTable))+1:1;
var fnSetupHeaderCell=function(elCell, zIndex)
{
var elDivWrapper=document.createElement("div");
elDivWrapper.setAttribute("style", "-moz-box-shadow: 3px 3px 4px #aaaaaa; -webkit-box-shadow: 3px 3px 4px #aaaaaa; box-shadow: 3px 3px 4px #aaaaaa;");
elDivWrapper.style.zIndex=zIndex;
elDivWrapper.style.backgroundColor="#0000ee";
elDivWrapper.style.color="white";
elDivWrapper.style.padding="3px";
elDivWrapper.className="DivWrapper";
elDivWrapper.style.position="relative";
while(elCell.childNodes.length)
elDivWrapper.appendChild(elCell.childNodes[0]);
elCell.appendChild(elDivWrapper);
};
if(bVertical)
for(var r=bHorizontal?1:0; r<elTable.rows.length; r++)
fnSetupHeaderCell(elTable.rows[r].cells[0], zIndex);
if(bHorizontal)
for(var c=bVertical?1:0; c<elTable.rows[0].cells.length; c++)
fnSetupHeaderCell(elTable.rows[0].cells[c], zIndex);
_table_make_fixed_header_reposition(elTable.id, bHorizontal, bVertical, bWrappedByScrollableDiv);
//this could be CPU intensive, depending on the number of events fired and size of the table.
var onScrollEventHandler=function(ev){
_table_make_fixed_header_reposition(elTable.id, bHorizontal, bVertical, bWrappedByScrollableDiv);
};
var elScrollable=bWrappedByScrollableDiv?elTable.parentNode:window;
if(elScrollable.addEventListener)
elScrollable.addEventListener('scroll', onScrollEventHandler, false);
else if (elScrollable.attachEvent)
elScrollable.attachEvent('scroll', onScrollEventHandler);
//this is undesired for performance reasons, hooks and event listeners are prefered instead.
if(nRepositionIntervalMilliseconds>0)
setInterval("_table_make_fixed_header_reposition('"+elTable.id+"', "+(bHorizontal?"true":"false")+", "+(bVertical?"true":"false")+", "+(bWrappedByScrollableDiv?"true":"false")+")", nRepositionIntervalMilliseconds);
}
function _table_make_fixed_header_reposition(strTableID, bHorizontal, bVertical, bWrappedByScrollableDiv)
{
var elTable=document.getElementById(strTableID);
var strLeft;
var strTop;
if(bWrappedByScrollableDiv)
{
strLeft
=Math
.min(Math
.max(elTable
.parentNode
.scrollLeft
-elTable
.offsetLeft
+elTable
.parentNode
.offsetLeft
, 0), elTable
.offsetWidth
)+"px"; strTop
=Math
.min(Math
.max(elTable
.parentNode
.scrollTop
-elTable
.offsetTop
+elTable
.parentNode
.offsetTop
, 0), elTable
.offsetHeight
)+"px"; }
else
{
strLeft
=Math
.min(Math
.max(f_scrollLeft
()-elTable
.offsetLeft
, 0), elTable
.offsetWidth
)+"px"; strTop
=Math
.min(Math
.max(f_scrollTop
()-elTable
.offsetTop
, 0), elTable
.offsetHeight
)+"px"; }
if(bVertical)
for(var r=bHorizontal?1:0; r<elTable.rows.length; r++)
elTable.rows[r].cells[0].childNodes[0].style.left=strLeft;
if(bHorizontal)
for(var c=bVertical?1:0; c<elTable.rows[0].cells.length; c++)
elTable.rows[0].cells[c].childNodes[0].style.top=strTop;
}
//http://www.softcomplex.com/docs/get_window_size_and_scrollbar_position.html
function f_scrollLeft(){
return f_filterResults (
window.pageXOffset ? window.pageXOffset : 0,
document.documentElement ? document.documentElement.scrollLeft : 0,
document.body ? document.body.scrollLeft : 0
);
}
function f_scrollTop() {
return f_filterResults (
window.pageYOffset ? window.pageYOffset : 0,
document.documentElement ? document.documentElement.scrollTop : 0,
document.body ? document.body.scrollTop : 0
);
}
function f_filterResults(n_win, n_docel, n_body) {
var n_result = n_win ? n_win : 0;
if (n_docel && (!n_result || (n_result > n_docel)))
n_result = n_docel;
return n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
}
//you should add an event handler for onload here
</script>
</head>
<body>
<p>
Vertical and horizontal th cells should remain visible and aligned while scrolling.<br>
This solution does not use any frameworks. Feel free to replace existing helpers (scroll offsets) using jquery or prototype (or any other framework).
</p>
<div style="width: 800px; height: 600px; overflow: scroll">
<table class="TableLarge" id="mySpecialHugeTable">
<tr>
<th>Fixed!</th>
<th>Fixed!</th>
<th>Fixed!</th>
<th>Fixed!</th>
<th>Fixed!</th>
<th>Fixed!</th>
<th>Fixed!</th>
<th>Fixed!</th>
<th>Fixed!</th>
</tr>
<tr>
<th>Fixed!</th>
<td>My mother has apples.</td>
<td>My mother has apples.</td>
<td>The goose is pretty.</td>
<td>Hello world!</td>
<td>This is a very short story...Real short.</td>
<td>Umm...how is this done again?</td>
<td>Umm...how is this done again?</td>
<td>I think Javascript is some kind of Voodoo on the DOM.</td>
</tr>
<tr>
<th>Fixed!</th>
<td>The goose is pretty.</td>
<td>Hello world!</td>
<td>Umm...how is this done again?</td>
<td>Umm...how is this done again?</td>
<td>My mother has apples.</td>
<td>I think Javascript is some kind of Voodoo on the DOM.</td>
<td>This is a very short story...Real short.</td>
<td>This is a very short story...Real short.</td>
</tr>
<tr>
<th>Fixed!<br>multi-line</th>
<td>My mother has apples.</td>
<td>I think Javascript is some kind of Voodoo on the DOM.</td>
<td>I think Javascript is some kind of Voodoo on the DOM.</td>
<td>Hello world!</td>
<td>This is a very short story...Real short.</td>
<td>The goose is pretty.</td>
<td>The goose is pretty.</td>
<td>Umm...how is this done again?</td>
</tr>
<tr>
<th>Fixed!</th>
<td>My mother has apples.</td>
<td>Umm...how is this done again?</td>
<td>The goose is pretty.</td>
<td>The goose is pretty.</td>
<td>This is a very short story...Real short.</td>
<td>Hello world!</td>
<td>Hello world!</td>
<td>I think Javascript is some kind of Voodoo on the DOM.</td>
</tr>
</table>
</div>
<div id="padding_for_test"> </div>
<script type="text/javascript">
table_make_fixed_header(document.getElementById("mySpecialHugeTable"), /*bHorizontal*/ true, /*bVertical*/ true, 1000, /*bWrappedByScrollableDiv*/ true);
</script>
</body>
</html>