I have a Gantt chart type web control: an html table of cells (one cell represents one day for example) and some absolutely positioned divs representing the bars - the parent element of the div is the appropriate start TD. I set the width of the divs so that they cover the appropriate number of days. The width is calculated by summing the offsetWidth values of the cells covered by the div.
This works correctly in IE7, Chrome and Opera (and I think in Firefox 2) but not in Firefox 4. The lengths of the div are sometimes too short sometimes too long. From looking into the problem it seems that it's to do with a sub-pixel problem similar to that described here
What I'm seeing (see the source html below) is that my 100% wide table (its offsetWidth reported to be 1311 px ) is divided into 30 cells which on average should take 43.7 px. Obviously it has to use whole numbers but Firefox 4 reports every cell to have an offsetWidth = 44 pixels, thus for a div that covers every cell its offsetWidth is 1320 pixels (9 pixels to large). Apparently the table conserves its width of 1311 px indicating the cell offsetWidth is probably reporting 44 when in some cases the cell physically takes 43 pixels
Comparing to chrome and opera and IE7 the offsetWidth of the cells are a mixture of 44 and 43 pixels but adding up to the correct final width of 1311.
The question is how can I work around this behaviour of Firefox4 to make sure my divs have the correct length.
I've not yet tested on other versions of IE
Here's a simplified working example of the problem:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1">
<title>Planner Test</title>
<style type="text/css">
body
{
font-size:10px;
}
table
{
width:100%;
border-collapse:collapse;
border-spacing:0px;
table_layout:fixed;
margin: 0px 0px 0px 0px;
padding: Opx 0px 0px 0px;
}
table td,
table th
{
overflow: hidden;
vertical-align:top;
height:19px;
border:1px solid red;
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
div.PlannerItem
{
text-al开发者_JAVA技巧ign:right;
overflow: hidden;
position:absolute;
height:16px;
border: solid 0px black;
background-color: yellow;
color: #334575;
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
</style>
<script type="text/javascript">
//<![CDATA[
function WIDTH( el ) {
// use offsetWidth - supposed to be most consistent accross browsers
return parseInt( el.offsetWidth );
}
function createRows()
{
var nbCells = 30; // set to vary the number of cells
var thead = document.getElementById( "tablehead" );
var fragment = document.createDocumentFragment();
var row = document.createElement( "tr" );
var th;
// create header row % width calculated from nbCells
for( i = 0; i < nbCells; i++ ) {
th = document.createElement( "th" );
th.style.width = (100.0 / nbCells) + "%";
row.appendChild( th );
}
fragment.appendChild(row);
thead.appendChild(fragment );
// body rows
var tbody = document.getElementById( "tablebody" );
for ( i = 0; i < nbCells; i++ ) {
fragment = document.createDocumentFragment();
row = document.createElement("tr");
for ( j = 0; j < nbCells; j++ ) {
var cell = document.createElement( "td" );
if ( j == 0 ) {
var div = document.createElement("div");
div.className = "PlannerItem";
cell.appendChild( div );
}
row.appendChild( cell );
}
fragment.appendChild(row );
tbody.appendChild( fragment );
}
setWidths();
}
function setWidths()
{
var rows = document.getElementsByTagName( "tr" );
// show cell widths in header
cells = rows[0].getElementsByTagName( "th" );
for( i = 0; i < cells.length; i++ ) {
cells[i].innerHTML = WIDTH(cells[i]);
}
// calculate widths for divs
for( i = 1; i < rows.length; i++ ) {
var cells = rows[i].getElementsByTagName( "td" );
var width = 0;
var div = cells[0].firstChild;
for( j = 0; j < i; j++ ) {
width += parseInt( WIDTH( cells[j]) );
}
div.style.width = width + "px";
div.innerHTML = WIDTH(div);
}
}//]]>
</script>
</head>
<body onload='createRows();'>
<form id="form1" runat="server" >
<table id="tab">
<thead id="tablehead">
</thead>
<tfoot></tfoot>
<tbody id='tablebody'></tbody>
</table>
</form>
</body>
</html>
Looks like using getBoundingClientRec() instead of offsetWidth (see http://weblogs.mozillazine.org/roc/archives/2008/01/subpixel_layout.html) fixes the problem - Need to calculate the div width using this value so as not to lose precision: The divs line up with the cells correctly in this case
精彩评论