-
-
Save i-scorpion/2948136 to your computer and use it in GitHub Desktop.
Here is a simple jQuery plugin to make a table header fixed on top when window is scrolled. | |
Using the code from twitter bootstrap documentation page, this code is customized for table header. | |
Create the table with following layout - | |
<table class="table-fixed-header"> | |
<thead class="header"> | |
<tr> | |
<th>Column 1</th> | |
<th>Column 2</th> | |
<th>Column 3</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr> | |
<td>Data Column 1</td> | |
<td>Data Column 2</td> | |
<td>Data Column 3</td> | |
</tr> | |
... | |
</tbody> | |
</table> | |
Add the css from the file "table-fixed-header.css" | |
To apply it to above table, call - | |
$('.table-fixed-header').fixedHeader(); | |
It can take two parameters - | |
bgColor - background color of the fixed header | |
topOffset - offset from top of windows where the fixed-header will be positioned (default is 40) | |
If you use any other value for topOffset, update the "top" parameter CSS as well accordingly. | |
For example, if there is no fixed navbar, you can set topOffset to 0 - | |
$('.table-fixed-header').fixedHeader({topOffset: 0}); | |
Also update the CSS to - top: 0; |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Table Fixed Header</title> | |
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css"> | |
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script> | |
<!-- CSS and JS for table fixed header --> | |
<link rel="stylesheet" href="table-fixed-header.css"> | |
<script src="table-fixed-header.js"></script> | |
<style type="text/css"> | |
#mynav { | |
top: 0; | |
position: fixed; | |
left: 0; | |
right: 0; | |
margin: 0 auto; | |
z-index: 1030; | |
height:40px; | |
color:#fff; | |
background-color:#666; | |
text-align: center; | |
} | |
body { padding-top:60px; } | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h2 id="mynav">| my navigation bar | my navigation bar | my navigation bar | my navigation bar |</h2> | |
<h1>Table Fixed Header</h1> | |
<table id="mytable" class="table table-bordered table-striped table-fixed-header"> | |
<thead class="header"> | |
<tr> | |
<th>Column 1</th> | |
<th>Column 2</th> | |
<th>Column 3</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr> | |
<td>Data Column 1</td> | |
<td>Data Column 2</td> | |
<td>Data Column 3</td> | |
</tr> | |
</tbody> | |
</table> | |
<h1>Another table</h1> | |
<table id="mytable2" class="table table-bordered table-striped table-fixed-header"> | |
<thead class="header"> | |
<tr style="color:#00f;"> | |
<th>Column 11</th> | |
<th>Column 22</th> | |
<th>Column 33</th> | |
<th>Column 44</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr> | |
<td>Data Column 11</td> | |
<td>Data Column 22</td> | |
<td>Data Column 33</td> | |
<td>Data Column 44</td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
<script language="javascript" type="text/javascript" > | |
$(document).ready(function(){ | |
// add 30 more rows to the table | |
var row = $('table#mytable > tbody > tr:first'); | |
var row2 = $('table#mytable2 > tbody > tr:first'); | |
for (i=0; i<30; i++) { | |
$('table#mytable > tbody').append(row.clone()); | |
$('table#mytable2 > tbody').append(row2.clone()); | |
} | |
// make the header fixed on scroll | |
$('.table-fixed-header').fixedHeader(); | |
}); | |
</script> | |
</body> | |
</html> |
table .header-fixed { | |
position: fixed; | |
top: 40px; | |
z-index: 1020; /* 10 less than .navbar-fixed to prevent any overlap */ | |
border-bottom: 1px solid #d5d5d5; | |
-webkit-border-radius: 0; | |
-moz-border-radius: 0; | |
border-radius: 0; | |
-webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 5px rgba(0,0,0,.1); | |
-moz-box-shadow: inset 0 1px 0 #fff, 0 1px 5px rgba(0,0,0,.1); | |
box-shadow: inset 0 1px 0 #fff, 0 1px 5px rgba(0,0,0,.1); | |
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */ | |
} |
(function($) { | |
$.fn.fixedHeader = function (options) { | |
var config = { | |
topOffset: 40, | |
bgColor: '#EEEEEE' | |
}; | |
if (options){ $.extend(config, options); } | |
return this.each( function() { | |
var o = $(this); | |
var $win = $(window) | |
, $head = $('thead.header', o) | |
, isFixed = 0; | |
var headTop = $head.length && $head.offset().top - config.topOffset; | |
function processScroll() { | |
if (!o.is(':visible')) return; | |
var i, scrollTop = $win.scrollTop(); | |
var t = $head.length && $head.offset().top - config.topOffset; | |
if (!isFixed && headTop != t) { headTop = t; } | |
if (scrollTop >= headTop && !isFixed) { isFixed = 1; } | |
else if (scrollTop <= headTop && isFixed) { isFixed = 0; } | |
isFixed ? $('thead.header-copy', o).removeClass('hide') | |
: $('thead.header-copy', o).addClass('hide'); | |
} | |
$win.on('scroll', processScroll); | |
// hack sad times - holdover until rewrite for 2.1 | |
$head.on('click', function () { | |
if (!isFixed) setTimeout(function () { $win.scrollTop($win.scrollTop() - 47) }, 10); | |
}) | |
$head.clone().removeClass('header').addClass('header-copy header-fixed').appendTo(o); | |
var ww = []; | |
o.find('thead.header > tr:first > th').each(function (i, h){ | |
ww.push($(h).width()); | |
}); | |
$.each(ww, function (i, w){ | |
o.find('thead.header > tr > th:eq('+i+'), thead.header-copy > tr > th:eq('+i+')').css({width: w}); | |
}); | |
o.find('thead.header-copy').css({ margin:'0 auto', | |
width: o.width(), | |
'background-color':config.bgColor }); | |
processScroll(); | |
}); | |
}; | |
})(jQuery); |
THIS
IS
SUPERB!!!
Thanks!
Hi !
Thank you for this amazing plug-in which work very well ! I've a question : I use Ajax to create dynamically my table and then i call this plug-in to create the fixed header. How to destroy a fixed header if it already created ?
Thanks for your answer !
Plugin has one problem:
when the width of the columns changes, the width of the column float-header remains unchanged
For example, when you change the width of the browser window
Or when added to the table new lines (on ajax), and the width of the columns changes slightly
I see the decision to add an event handler to change the width of columns in a table,
but it was necessary to add plugin jquery.ba-resize.min.js and make some changes to bootstrap-table-fixed-header.js
var resizeHead = function(o)
{
var ww = [];
o.find('thead.header > tr:first > th').each(function (i, h){
ww.push($(h).width());
});
$.each(ww, function (i, w){
o.find('thead.header > tr > th:eq('+i+'), thead.header-copy > tr > th:eq('+i+')').css({width: w});
});
o.find('thead.header-copy').css({ margin:'0 auto',
width: o.width(),
'background-color':config.bgColor });
}
resizeHead(o);
$(o.find('thead.header > tr:first > th')).resize(function(e){
resizeHead(o);
});
Maybe you know, how it's make better
Heres a much more simple way to keep the fixed header the same width as the original table:
$(window).on('resize', function () {
$('.header-copy').width($('.table-fixed-header').width())
});
Fixed Header bar is always displaying on top of the window, what should i do if i need to wrap in a div having class name table box.
Problem: The div having class name table box is in middle of the window. if i trying to scoll the fixed bar is displaying on the top of the window. I want it to be displayed it in the box named table box.
Please do the Needful.
One other approach is to use wrapping div's to absolutely position the fixed header at the top, while the table scrolls inside the div with a hidden overflow. The header will never float off the table, but, then you have hidden content, which may not be desired.
https://gist.github.com/straydogstudio/5921932 (two forks off this gist)
Because this code uses a duplicate table with the same classes, duplicate styling for the header should not be needed.
Thanks for the code by the way.
There is a bug that the header-copy thead always displays at the bottom of the table under the IE7.(also IE6)
Thank. This is a good solution!
Thank you for grate plugin.
I'm facing a problem in my MVC 3 application when I'm using this.
At one point the headers position changes ( to left) when scrolling down. It will be coming back to same position when continuing the scrolling but is there any way to fix it.
thanks for the plugin, best one I found to work with bootstrap.
o.find('thead.header > tr:first > th').each(function (i, h){
ww.push($(h).outerWidth(true));
});
....
o.find('thead.header-copy').css({ margin:'0 auto',
'margin-left': '-1px',
width: o.outerWidth(),
'background-color':config.bgColor });
updated example in my fork, now you may see it in action http://bl.ocks.org/just-boris/raw/7427348/
@vkorichov: your autoWidth(true)
fix gives me much better results than the original width()
.
I'm using twitter bootstrap's table-condensed
class and my headers sometimes have a few words in them instead of just one short word. Perhaps that's the reason why the original doesn't work well for me?
Anyway, your fix is a good one.
Thanks just-boris, your example clarified me!
Great job.
Also for me:
reinout commented 6 months ago
@vkorichov: your autoWidth(true) fix gives me much better results than the original width().
+1 for just-boris' change to autoWidth(true)
This works awesome. Thanks for all the hard work folks. I just have one small issue if someone can help me? I have a drop down menu (select list) just above the table and the drop down list gets hidden behind the Table Row. Is there a way I could have my Drop Down not get hidden behind?
Hey, I have a problem with large horizontal tables. What about scrolling right or left? I just want the header to be fixed vertically, not horizontally.
Any idea?
My contribution:
Having an issue in Safari on Mac OSX. When a table goes off the page horizontally the headers are no longer lined up correctly. Otherwise, they show fine. Any ides what may be causing this?
This jquery plugin fixed the width calculation issue.My page width is 'auto' and width of my page as well as header is nearly 1500px. Therefore I have horizontal scroll bar for it. But this fix has freezed the header at the top and when I scroll horizontally it remain frizzed and hides some of the header rows. Please help.
Thank you for this code! I found, however, that it leaked memory if the table is being replaced often, as it is the case in single page apps, for example. So I rewrote it a little, adding the resize support also. Since I am using Bootstrap 3, the .width()
function was not enough, so I changed it to .outerWidth()
and everything is fine.
The main difference with this version is the thead
class name, and the optional data-fixed-header-*
attributes.
<table data-fixed-header-top-offset="100" data-fixed-header-bg-color="white">
<thaad class="fixed-header">
<th>...</th>
....
</thead>
<tbody>
...
</tbody>
...
</table>
Note: if the table
has the CSS class table-fixed-header
, then no JS is required at all, and it will automatically be picked up by the plugin.
define([
'jquery'
], function ($) {
var baseConfig = {
topOffset: 40,
bgColor: '#EEEEEE'
};
var $win;
function processResizeColumns(table, header) {
var headerCopy = table.find('thead.fixed-header-copy > tr:first')
.css('width', table.outerWidth())
;
$('tr:first > th', header).each(function (i, h){
headerCopy.find('th:eq('+i+')').css('width', $(h).outerWidth() );
});
}
function processScroll(table, header) {
var scrollTop;
var headTop;
var isFixed;
if (!table.is(':visible')) {
return;
}
isFixed = header.data('isFixed');
headTop = header.length && header.offset().top - header.data('topOffset');
scrollTop = $win.scrollTop();
if (scrollTop >= headTop && !isFixed) {
isFixed = 1;
} else if (scrollTop <= headTop && isFixed) {
isFixed = 0;
}
isFixed ? $('thead.fixed-header-copy', table).removeClass('hide')
: $('thead.fixed-header-copy', table).addClass('hide');
header.data('isFixed', isFixed);
}
$.fn.fixedHeader = function (options) {
options = $.extend({}, baseConfig, options || {});
return this.each( function() {
var table = $(this);
var header = $('thead.fixed-header', table);
var config;
if (table.find('thead.fixed-header-copy').length || !header.length) {
return;
}
table.addClass('table-fixed-header');
config = $.extend({
topOffset: table.data('fixed-header-top-offset'),
bgColor: table.data('fixed-header-bg-color')
}, options);
// hack sad times - holdover until rewrite for 2.1
header.on('click', function () {
if (!header.data('isFixed')) {
setTimeout(function () {
$win.scrollTop($win.scrollTop() - 47); // not sure what this is for (yr)
}, 10);
}
}).data('topOffset', config.topOffset);
header.clone()
.removeClass('fixed-header')
.addClass('fixed-header-copy')
.css({
position: 'fixed',
margin:'0 auto',
top: config.topOffset + 'px',
backgroundColor: config.bgColor,
zIndex: 1020 /* 10 less than .navbar-fixed to prevent any overlap */
})
.appendTo(table);
processResizeColumns(table, header);
processScroll(table, header);
});
};
$(function () {
$win = $(window).on('resize', function () {
$('table.table-fixed-header').each(function () {
processResizeColumns($(this), $('thead.fixed-header', this));
});
}).on('scroll', function () {
$('table.table-fixed-header').each(function () {
processScroll($(this), $('thead.fixed-header', this));
});
});
// auto set on domcument ready
$('table.table-fixed-header').fixedHeader();
});
});
Note: no CSS is required.
@Tristanlogd your issue is that the original code sets the header to the table width on initialize. When the windows goes small, the width of the columns are set smaller, therefore no problem. But when the window size is resized larger (after init), then the columns's width do not go beyound the table header width previously set. My last snippet fixes this.
Works great. Thanks 😀
Thumbup to @vkorichkov's OuterWidth
fixed.
It's working perfectly on Chrome but not on Safari. :(
Don't work for me.
But when the window size is resized larger (after init), then the columns's width do not go beyound the table header width previously set. My last snippet fixes this.
Can you post a sample code please? (jquery newbie here)
Thank you. This plugin will help me a lot.