OK, I found a solution. Fiddle here.
Strategy:
Use a hidden table to glean the desired cell widths of the visible table.
Tactic:
In addition to the table that the user shall see, a hidden "shadow" table, with identical content, must be created directly above the visible table.
The shadow table must allow the content to wrap inside the cells (this is default table
behavior).
When the page has loaded and at every window resize, show()
the shadow table, measure the width
of every td
in the top row, then hide()
the shadow table. Then copy the width
values to the corresponding td
elements in the visible table, which must have Chris Coyier's truncate applied.
Works in all browsers I've tested, including mobile.
Bonus tips:
- Use
­
to wrap long words if necessary, and
to stop words from wrapping. This can be applied only in the shadow table.
- Use
1px
more cell padding in the shadow table due to a bug in Internet Explorer - otherwise, IE's visible table sometimes becomes slightly wider than the shadow table.
JavaScript (requiring jQuery):
<script type="text/javascript">
function loadEvents() {
initFluidTables();
}
// Resize fluid table(s)
function resizeFluidTables() {
// Show source cells
$( ".fluid-table-invisible-source" ).show(0);
var fluidTableCellWidth = [];
// Measure (normally invisible) source cells
$( ".fluid-table-invisible-source td" ).each(function( index, value ) {
fluidTableCellWidth[index] = $( this ).width();
});
// Resize (always visible) target cells. Adding 1 pixel due to apparent bug in Firefox.
$( ".fluid-table-visible-target td>i" ).each(function( index, value ) {
$( this ).css({'width': fluidTableCellWidth[index]+1 });
});
// Re-hide source cells
$( ".fluid-table-invisible-source" ).hide();
}
// Create table(s) to be fluid
function initFluidTables() {
// Create a container. Not really necessary, but keeps DOM tidier.
$(".fluid-table").wrap( "<div></div>" );
// This looks like a mess. What it does, is that .fluid-table duplicates itself, and each sibling gets a different class.
$(".fluid-table").each(function() {
$( this ).clone().appendTo( $( this ).addClass( "fluid-table-invisible-source" ).parent() ).addClass( "fluid-table-visible-target" );
});
// Add truncating element inside target cells
$(".fluid-table-visible-target td").wrapInner( "<i></i>");
// Truncate table contents at first drawing of the DOM and every time the window resizes
resizeFluidTables();
$( window ).resize(function() {
resizeFluidTables();
});
}
</script>
CSS:
.fluid-table td { padding-right: 5px; }
.fluid-table td:nth-child(odd) { color: #aaa; }
.fluid-table-visible-target td>i {
font-style: inherit;
white-space: nowrap;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
/* source slighly more padded than target due to IE bug */
.fluid-table-invisible-source td:nth-child(even) {
padding-right: 10px;
}
.fluid-table-visible-target td:nth-child(even) {
padding-right: 9px;
}
Sample table:
Note use of ­
and
to indicate where you (do not) want the text to truncate.
<table class="fluid-table">
<tr>
<td>Avail­able <i>until</i>:</td><td>No expiry date</td><td>Avail­ability:</td><td>Worldwide</td><td></td>
</tr><tr>
<td>Year:</td><td>2016</td><td>Length:</td><td>29 minutes</td><td></td>
</tr><tr>
<td>First broad­cast:</td><td>Feb 2</td><td>Last broad­cast:</td><td>Feb 3</td><td></td>
</tr>
</table>