views:

13697

answers:

13

I've three divs. Header, central and footer. There is a table in central div (gridview) which is almost always longer than outer div. So I've made this div scrollable vertically. The question is: how can I make table header that it would be visible after div is scrolled down? I could have done this header with separate div or table and make it fixed but widths of columns in the table are not always the same - so I don't know how to maintain widths of columns in header then. Any clue?

+2  A: 

You would have to put the header outside the scrollable div. Everything within the div will scroll.

EDIT

Regarding the width if you go for a separate header, I can see a few solutions:

  • Assuming this is dynamic content, generate "fixed" widths based on the length of the string. Obviously specify in terms of EMs and leave some margin for error.
  • Use javascript.
  • Use fixed width columns.

I haven't actually tried the first, and it might be overcomplicating things a bit. It's something to try if you're desperate for the effect though.

I should also mention that there are probably javascript libraries with table widgets that do this already. Have a look at them to see how they do it.

Draemon
You are right but what about width of every column in header? Width of columns is not fixed and depends on data it changes. So how to maintain it when the header is separate?
rafek
+1  A: 

You need to put a table with the headers about your table of data. You can maintain the column width with table-layout:fixed. JavaScript can be used to match the column widths.

Greg
+1  A: 

I haven't tested this, but perhaps you could generate the table twice, once in the header and once in the scrolling div. Then in the header, make all the rows except the heading row invisible. Perhaps with 'display: none' or set their height to zero.

noswonky
I've checked this. It works - but I can't call it "the solution" of this problem.
rafek
this is horrible for accessibility
annakata
+5  A: 

Here is a basic solution using javascript:

function position(table) {
 table.rows[0].style.position="absolute";
 table.rows[0].style.top="0px";
 table.style.marginTop = table.rows[0].clientHeight/1.2;
 var widths = Array();
 for(var i = 0; i < table.rows[0].cells.length; i++) {
  widths[i] = max(table.rows[0].cells[i].clientWidth, table.rows[1].cells[i].clientWidth);
 }
 for(var row = 0; row < table.rows.length; row++) {
  for(var col = 0; col < widths.length; col ++) {
   table.rows[row].cells[col].style.width = widths[col] + "px";
  }
 }
}

function max(num1, num2) { return (num1 > num2) ? num1 : num2; }

You can see an example in action here: http://lynet.ca/~alumb/table.htm

alumb
The linked example no longer exists.I had trouble getting this working, and went with the "Stupid Fixed Header" solution mentioned below.
LeBleu
I won't vote this one. It simply fixes each row to the top of the page not something that will work in a page which has anything more then just this table on the page.
Hemant Tank
+1  A: 

Here's a nice solution (mostly CSS) which uses fixed width columns: http://www.imaputz.com/cssStuff/bulletVersion.html

And here's a bit of jQuery code to fix cell-widths when cell contents take more width than the fixed width:

<script
  src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"
  type="text/javascript"></script>
<script>
$(function() {
  $('div.tableContainer').each(function() { // for each table
    var div = $(this);
    var widths = [];
    var changed = false;
    $('table>*>tr', div).each(function(tr_i) {
      $(this).children().each(function(i) {
     var w = $(this).width();
     if (w > widths[i]) {
      widths[i] = w;
      changed = true;
     }
      });
    }).each(function(tr_i) {
      if (changed)
      $(this).children().each(function(i) {
        var width = widths[i];
     // add some width for scrollbar
     if (tr_i == 0 && changed && i == widths.length-1) width += 16;
     // insert a div to ensure width
        $(this).append('<div style="width:'+width+'px; height:0px">&nbsp;</div>');
      });
    });
    div.width(div.children('table').width()).css('overflow-x', 'hidden');
  });
});
</script>

The output is a bit off in IE when using a non-strict DTD. Tweak the widths in the CSS if you can't use standards mode.

Note that the jQuery code increases the table width at the end, and disables the horizontal scrollbar. You may or may not want that.

waqas
+2  A: 

You may try the jQuery plugin Stupid Fixed Header. The technique is basically the same: clone a header and put it on top of the table layer.

jackysee
+1  A: 

Take a look at YUI Data Table if you are looking for a comprehensive cross-browser implementation. I believe this is done by creating another table with matching column widths.

There appears to be tricks required to fix column widths. If I recall correctly, Firefox requires <col/> tags to be present.

In any case, there were many tricks employed in YUI DataTable (50k lines). You'd be well advised to look at it and decide how far you'd like to go on your own with this.

Chui Tey
+1  A: 

This solution works using CSS in Firefox and the other Gecko browsers, and CSS expressions in IE.

http://home.tampabay.rr.com/bmerkey/examples/nonscroll-table-header.html

The header and footer do not stay fixed in Opera or Safari/Chrome, but the whole table is scrollable so it is usable. Note that the columns are given percentage widths in the author's example, but they can be removed.

If you want to experiment with Opera/Safari/Chrome support, look at giving the tbody display:block and go from there.

Andrew Duffy
+2  A: 

What you actually want to be doing is making the <tbody> of the data table scrollable, so the <thead> and <tfoot> will remain naturally fixed.

Whilst this is trivial for FF et al:

tbody
{
    height: 100px; /* or whatever */
    overflow: auto;
    overflow-y: auto;
    overflow-x: hidden;
}

IE has severe and complex issues with tbody in general. It can be solved with expressions but it's non-trivial, and specific to the design.

annakata
+1  A: 

Isn't this sort of the same (i.e. duplicate) as How can I lock the first row and first column of a table when scrolling, possibly using javascript and CSS?

scraimer
+2  A: 

I've just put together a jQuery plugin that does exactly what you want. Its very small in size and really easy to implement.

All that is required is a table that has a thead and tbody.

You can wrap that table in a DIV with a classname and the table will always resize to fit in that div. so for example if your div scales with the browser window so will the table. The header will be fixed when scrolling. The footer will be fixed (if you enable a footer). You also have the option to clone the header in the footer and have it fixed. Also if you make your browser window too small and all columns can't fit...it will also scroll horizontally (header too).

you just pass the DIV's classname to the plugin like so: $('.myDiv').fixedHeaderTable({footer: true, footerId: 'myFooterId'}); and the plugin will do the rest. FooterID is a element on the page that contains the mark-up for your footer. this is used if you want to have pagination as your footer.

If you have multiple tables on the page it will also work for each table you want to have a fixed header.

check it out here: http://fixedheadertable.mmalek.com/

Keep in mind its still 'beta' so I am adding new features and bug fixes daily.

Supported browsers: IE6, IE7, IE8, FireFox, Safari, and Chrome

Mark
+1  A: 

I know this is a bit of an old post, but I have a really simple solution to this using CSS and a small jQuery script. It even allows the user to toggle the locking header feature on and off.

Check it out:

http://www.bobthegeek.com/?p=12

Bob

Bob Gibilaro
A: 

Hi,

Check http://s7u.blogspot.com, it has full information about scrollable tables. It uses CSS and JavaScript to make table scrollable. It has fixed header, footer and fixed columns.

Regards, Shahib

Shahib