In this example, when #content starts off 100px below #header, but as the user scrolls, #header stays in place. Of course it goes without saying that you'll want to make sure #header has a background so that its content will actually be visible when the two divs overlap. Have a look at the position property here: http://reference.sitepoint.com/css/position
I personally needed a table with both the left and top headers visible at all times. Inspired by several articles, I think I have a good solution that you may find helpful.
This version does not have the wrapping problem that other soltions have with floating divs or flexible/auto sizing of columns and rows.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script language="javascript" type="text/javascript" src="/Scripts/jquery-1.7.2.min.js"></script>
<script language="javascript" type="text/javascript">
// Handler for scrolling events
function scrollFixedHeaderTable() {
var outerPanel = $("#_outerPanel");
var cloneLeft = $("#_cloneLeft");
var cloneTop = $("#_cloneTop");
cloneLeft.css({ 'margin-top': -outerPanel.scrollTop() });
cloneTop.css({ 'margin-left': -outerPanel.scrollLeft() });
}
function initFixedHeaderTable() {
var outerPanel = $("#_outerPanel");
var innerPanel = $("#_innerPanel");
var clonePanel = $("#_clonePanel");
var table = $("#_table");
// We will clone the table 2 times: For the top rowq and the left column.
var cloneLeft = $("#_cloneLeft");
var cloneTop = $("#_cloneTop");
var cloneTop = $("#_cloneTopLeft");
// Time to create the table clones
cloneLeft = table.clone();
cloneTop = table.clone();
cloneTopLeft = table.clone();
cloneLeft.attr('id', '_cloneLeft');
cloneTop.attr('id', '_cloneTop');
cloneTopLeft.attr('id', '_cloneTopLeft');
cloneLeft.css({
position: 'fixed',
'pointer-events': 'none',
top: outerPanel.offset().top,
'z-index': 1 // keep lower than top-left below
});
cloneTop.css({
position: 'fixed',
'pointer-events': 'none',
top: outerPanel.offset().top,
'z-index': 1 // keep lower than top-left below
});
cloneTopLeft.css({
position: 'fixed',
'pointer-events': 'none',
top: outerPanel.offset().top,
'z-index': 2 // higher z-index than the left and top to make the top-left header cell logical
});
// Add the controls to the control-tree
clonePanel.append(cloneLeft);
clonePanel.append(cloneTop);
clonePanel.append(cloneTopLeft);
// Keep all hidden: We will make the individual header cells visible in a moment
cloneLeft.css({ visibility: 'hidden' });
cloneTop.css({ visibility: 'hidden' });
cloneTopLeft.css({ visibility: 'hidden' });
// Make the lef column header cells visible in the left clone
$("#_cloneLeft td._hdr.__row").css({
visibility: 'visible',
});
// Make the top row header cells visible in the top clone
$("#_cloneTop td._hdr.__col").css({
visibility: 'visible',
});
// Make the top-left cell visible in the top-left clone
$("#_cloneTopLeft td._hdr.__col.__row").css({
visibility: 'visible',
});
// Clipping. First get the inner width/height by measuring it (normal innerWidth did not work for me)
var helperDiv = $('<div style="positions: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 100%;"></div>');
outerPanel.append(helperDiv);
var innerWidth = helperDiv.width();
var innerHeight = helperDiv.height();
helperDiv.remove(); // because we dont need it anymore, do we?
// Make sure all the panels are clipped, or the clones will extend beyond them
outerPanel.css({ clip: 'rect(0px,' + String(outerPanel.width()) + 'px,' + String(outerPanel.height()) + 'px,0px)' });
// Clone panel clipping to prevent the clones from covering the outerPanel's scrollbars (this is why we use a separate div for this)
clonePanel.css({ clip: 'rect(0px,' + String(innerWidth) + 'px,' + String(innerHeight) + 'px,0px)' });
// Subscribe the scrolling of the outer panel to our own handler function to move the clones as needed.
$("#_outerPanel").scroll(scrollFixedHeaderTable);
}
$(document).ready(function () {
initFixedHeaderTable();
});
</script>
<style type="text/css">
* {
clip: rect font-family: Arial;
font-size: 16px;
margin: 0;
padding: 0;
}
#_outerPanel {
margin: 0px;
padding: 0px;
position: absolute;
left: 50px;
top: 50px;
right: 50px;
bottom: 50px;
overflow: auto;
z-index: 1000;
}
#_innerPanel {
overflow: visible;
position: absolute;
}
#_clonePanel {
overflow: visible;
position: fixed;
}
table {
}
td {
white-space: nowrap;
border-right: 1px solid #000;
border-bottom: 1px solid #000;
padding: 2px 2px 2px 2px;
}
td._hdr {
color: Blue;
font-weight: bold;
}
td._hdr.__row {
background-color: #eee;
border-left: 1px solid #000;
}
td._hdr.__col {
background-color: #ddd;
border-top: 1px solid #000;
}
</style>
</head>
<body>
<div id="_outerPanel">
<div id="_innerPanel">
<div id="_clonePanel"></div>
<table id="_table" border="0" cellpadding="0" cellspacing="0">
<thead id="_topHeader" style="background-color: White;">
<tr class="row">
<td class="_hdr __col __row">
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
<td class="_hdr __col">
TOP HEADER
</td>
</tr>
</thead>
<tbody>
<tr class="row">
<td class="_hdr __row">
MY HEADER COLUMN:
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
</tr>
<tr class="row">
<td class="_hdr __row">
MY HEADER COLUMN:
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
<td class="col">
The quick brown fox jumps over the lazy dog.
</td>
</tr>
</tbody>
</table>
</div>
<div id="_bottomAnchor">
</div>
</div>
</body>
</html>
Instead of working with positioning and padding/margin and without knowing the header's size, there's a way to keep the header fixed by playing with the scroll.
After looking through all the answers, I found a slightly different way with minimum CSS and no JS, only the height of the header needs to be set correctly in #content, in this case 60px
In most case, it is better than using position: fixed, since position: fixed takes the element out of the regular flow of elements.
Note:
The HTML structure is important while using position: sticky, since it makes the element sticky relative to the parent. And the sticky positioning might not work with a single element made sticky within a parent.
The parent of the element made sticky should not have the overflow property set Eg: if parent has overflow: auto or overflow: hidden, then sticky positioning might not work
Giving at least one of the top, bottom, left, right is important because it makes the element sticky in relation to some position.
Run the snippet below to check a sample implementation.