2015 update: the flexbox approach
There are two other answers briefly mentioning flexbox; however, that was more than two years ago, and they don't provide any examples. The specification for flexbox has definitely settled now.
Note: Though CSS Flexible Boxes Layout specification is at the Candidate Recommendation stage, not all browsers have implemented it. WebKit implementation must be prefixed with -webkit-; Internet Explorer implements an old version of the spec, prefixed with -ms-; Opera 12.10 implements the latest version of the spec, unprefixed. See the compatibility table on each property for an up-to-date compatibility status.
(taken from https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes)
All major browsers and IE11+ support Flexbox. For IE 10 or older, you can use the FlexieJS shim.
To check current support you can also see here:
http://caniuse.com/#feat=flexbox
Working example
With flexbox you can easily switch between any of your rows or columns either having fixed dimensions, content-sized dimensions or remaining-space dimensions. In my example I have set the header to snap to its content (as per the OPs question), I've added a footer to show how to add a fixed-height region and then set the content area to fill up the remaining space.
html,
body {
height: 100%;
margin: 0;
}
.box {
display: flex;
flex-flow: column;
height: 100%;
}
.box .row {
border: 1px dotted grey;
}
.box .row.header {
flex: 0 1 auto;
/* The above is shorthand for:
flex-grow: 0,
flex-shrink: 1,
flex-basis: auto
*/
}
.box .row.content {
flex: 1 1 auto;
}
.box .row.footer {
flex: 0 1 40px;
}
<!-- Obviously, you could use HTML5 tags like `header`, `footer` and `section` -->
<div class="box">
<div class="row header">
<p><b>header</b>
<br />
<br />(sized to content)</p>
</div>
<div class="row content">
<p>
<b>content</b>
(fills remaining space)
</p>
</div>
<div class="row footer">
<p><b>footer</b> (fixed height)</p>
</div>
</div>
In the CSS above, the flex property shorthands the flex-grow, flex-shrink, and flex-basis properties to establish the flexibility of the flex items. Mozilla has a good introduction to the flexible boxes model.
The approach you suggest is not guaranteed to give you the result you're looking for - what if you had a tbody
for example:
<table id="myTable">
<tbody>
<tr>...</tr>
<tr>...</tr>
</tbody>
</table>
You would end up with the following:
<table id="myTable">
<tbody>
<tr>...</tr>
<tr>...</tr>
</tbody>
<tr>...</tr>
</table>
I would therefore recommend this approach instead:
$('#myTable tr:last').after('<tr>...</tr><tr>...</tr>');
You can include anything within the after()
method as long as it's valid HTML, including multiple rows as per the example above.
Update: Revisiting this answer following recent activity with this question. eyelidlessness makes a good comment that there will always be a tbody
in the DOM; this is true, but only if there is at least one row. If you have no rows, there will be no tbody
unless you have specified one yourself.
DaRKoN_ suggests appending to the tbody
rather than adding content after the last tr
. This gets around the issue of having no rows, but still isn't bulletproof as you could theoretically have multiple tbody
elements and the row would get added to each of them.
Weighing everything up, I'm not sure there is a single one-line solution that accounts for every single possible scenario. You will need to make sure the jQuery code tallies with your markup.
I think the safest solution is probably to ensure your table
always includes at least one tbody
in your markup, even if it has no rows. On this basis, you can use the following which will work however many rows you have (and also account for multiple tbody
elements):
$('#myTable > tbody:last-child').append('<tr>...</tr><tr>...</tr>');
Best Solution
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