4

This simple table with one absolutely-positioned column renders differently in Firefox (and IE) than in Chrome (and other Webkit-based browsers):

enter image description here

http://jsfiddle.net/WZ6x8/

<div>
    <table>
        <tr>
            <th class="absolute">&nbsp;</th>
            <th>&nbsp;</th>
        </tr>
    </table>
</div>

* {
    margin: 0;
    padding: 0;
}
table {
    border-collapse: collapse;
    table-layout:fixed;
}
th {
    border: 1px solid black;
    width: 100px;
}
.absolute {
    left: 0;
    position: absolute;
}
div {
    margin-left: 100px;
}

Why is there a difference? Which browser is wrong (according to the standard)? How can this be fixed to work on all browsers, without removing the line border-collapse: collapse?

Edit: as noted by @urzeit, "If you specify top: 0; the output in firefox is the same as in chrome." However, there are two issues: first, with multiple rows, top: 0; collapses them all into one; second, the right edge of the absolutely-positioned column extends one pixel too far. You can see both issues at http://jsfiddle.net/WZ6x8/3.

steveax
  • 17,527
  • 6
  • 44
  • 59
1''
  • 26,823
  • 32
  • 143
  • 200
  • Do you see a difference here: http://jsfiddle.net/WZ6x8/1/ ? – FelipeAls Feb 23 '14 at 19:52
  • 1
    I think the problem is the not-defined top. This seems to default to 1px in firefox and to 0px in other browsers. If you specify `top: 0;` the output in firefox is the same as in chrome. – urzeit Feb 23 '14 at 19:54
  • @urzeit Nice catch, thanks! However, there are two issues: first, with multiple rows, `top: 0;` collapses them all into one; second, the right edge of the absolutely-positioned column extends one pixel too far. You can see both issues at http://jsfiddle.net/WZ6x8/3/. – 1'' Feb 23 '14 at 20:47
  • @1“ try to add a Position:absolute without left and Top to the tr. This might help in the case of multiple rows. – urzeit Feb 24 '14 at 07:25
  • @urzeit But `top: 0;` is necessary to fix the bug, as you mentioned. Using margins, [this](http://jsfiddle.net/WZ6x8/4/) works on Chrome, and [this](http://jsfiddle.net/WZ6x8/5/) on Firefox. – 1'' Feb 24 '14 at 15:37
  • @1" add the `position: asolute` without `top` to the tr - AND to the th WITH `top`. – urzeit Feb 25 '14 at 09:00
  • @urzeit Is [this](http://jsfiddle.net/WZ6x8/6/) what you mean? In Firefox, it fixes the vertical positioning on the table header only, and the horizontal position on neither. I suppose this makes sense. – 1'' Feb 25 '14 at 13:58
  • Set `border-right: 1px solid black` just for last `th` http://jsfiddle.net/RS5s3/ – Nizamil Putra Feb 26 '14 at 00:09
  • @NizamilPutra Your example does get rid of the misalignment, but it uses `top: 0;` which means all the rows of the absolutely-positioned column collapse into 1. Is there a way to get the proper alignment without collapsing them? – 1'' Feb 26 '14 at 00:19
  • @1'' I'm not sure how to make `tr` in relative position. Based on CSS 2, Visual formatting model, 9.3.1 [w3.org] - _The effect of 'position:relative' on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption elements is undefined._ – Nizamil Putra Feb 26 '14 at 00:33
  • @NizamilPutra I was not suggesting to use `position:relative` - in fact, I am fairly sure that `position:absolute` is the only option. – 1'' Feb 26 '14 at 00:41
  • @1'' Yes, but if you want to make `position: absolute` works with parent tag, you should add `position: relative` in parent tag. IMHO. May I know what actually do you want? – Nizamil Putra Feb 26 '14 at 00:48
  • @NizamilPutra Specifically, I would like http://jsfiddle.net/WZ6x8/4/ to look the same in Chrome and Firefox. I do not think `position:relative` is necessary in the parent - the position of a `position:absolute` element is relative to `` if no ancestor with `position:relative` exists. – 1'' Feb 26 '14 at 01:51
  • @steveax I suspected this might be undefined behaviour. However, it is not nonsensical: I would like to make a less hacky version of [this answer](http://stackoverflow.com/a/1312678/1397061) that will work with expandable tables. What do you suggest instead, aside from some jQuery magic? – 1'' Feb 26 '14 at 03:26
  • I think part of the reason it extends too far is because the absposed cell is being sized according to the content-box model, which does not take the border width into account. Note that `top: 0` does not cause or influence this - you can see it in your original fiddle as well. You can force everything to use `box-sizing: border-box`, but [Chrome always being the outlier will react very differently](http://stackoverflow.com/questions/19068909/why-is-box-sizing-acting-different-on-table-vs-div/19069129#19069129). – BoltClock Feb 26 '14 at 04:41
  • @1'' Beside your question about the rendering issues, but why position the one table-cell absolute!? In your given example it would make no difference, so I absolutely see no reason for position absolute. – Netsurfer Feb 26 '14 at 11:12
  • @Netsurfer See my previous comment. – 1'' Feb 26 '14 at 15:27

4 Answers4

11

This is caused by rounding issues which are often inconsistent across browsers, and are probably the same ones that plague things like background offsets, percentage calculations and so on.

In a nutshell, the reason why rounding issues come into play is found in section 17.6.2 which, as you may have guessed, describes the collapsing border model:

Borders are centered on the grid lines between the cells. User agents must find a consistent rule for rounding off in the case of an odd number of discrete units (screen pixels, printer dots).

And:

The top border width of the table is computed by examining all cells who collapse their top borders with the top border of the table. The top border width of the table is equal to half of the maximum collapsed top border. The bottom border width is computed by examining all cells whose bottom borders collapse with the bottom of the table. The bottom border width is equal to half of the maximum collapsed bottom border.

Since the border width is 1 pixel, which is an odd number, rounding issues occur when attempting to halve that value. So the question of which browser is wrong — or if any of them are — is debatable.

Unfortunately, because this is a rounding issue, it's not possible to work around this using pure CSS unless through inconceivably elaborate hackery, and very difficult to do so using a script as browsers tend to be inconsistent when reporting decimal/fractional offset values as well (in particular, Firefox, IE and Chrome all report wildly different values for offsetTop of your table-cell and its next sibling).

While I can't offer a solution to your problem, hopefully at least I've helped you understand why browsers are behaving the way they do.


Here's the nitty gritty if you're interested in why the issue ultimately lies in the way the collapsing border model is defined.

Section 9.7 states that if an element is absolutely positioned, then its display is set to block, even if it would otherwise be a table-cell. In all browsers, the computed display for that th is in fact block, so no problem there.

As you've correctly pointed out, the containing block of your table cell is the initial containing block. This removes it from its usual containing block which would otherwise be the table. Section 10.6.4 does add that that if your cell does not have any specified height, top or bottom offsets, i.e. they are all auto, then it should remain in its static vertical position and measurements made accordingly. (Likewise the horizontal position is accounted for in section 10.3.7, however since you've given it left: 0 and width: 100px, it gets shifted to the left edge and its width is as specified, excluding the borders.)

But what is this static vertical position? Because it would ordinarily be display: table-cell if it wasn't absolutely-positioned, the static position, and its corresponding measurements, is determined by its position in the table.

Your given table layout is covered by the following subsections of section 17:

Section 17 contains elaborate descriptions on how tables, captions, table-rows and table-cells should be laid out. A lot of it is based on HTML, and certain sections are left vague and/or undefined for various reasons. Fixed table layout is pretty well-defined though, and in this case it is not even relevant.

Section 17.5 says this near the bottom:

The edges of the rows, columns, row groups and column groups in the collapsing borders model coincide with the hypothetical grid lines on which the borders of the cells are centered. (And thus, in this model, the rows together exactly cover the table, leaving no gaps; ditto for the columns.)

And:

Note. Positioning and floating of table cells can cause them not to be table cells anymore, according to the rules in section 9.7. When floating is used, the rules on anonymous table objects may cause an anonymous cell object to be created as well.

Which, of course, has been explained just above.

But if an absolutely-positioned table cell is no longer a cell, what happens?

A "missing cell" is a cell in the row/column grid that is not occupied by an element or pseudo-element. Missing cells are rendered as if an anonymous table-cell box occupied their position in the grid.

So while the actual th box is absolutely positioned, it leaves an anonymous "ghost" cell in its place in order for the table to be rendered properly. This anonymous table-cell is empty and does not inherit the styles from the actual table-cell, so it has no intrinsic width.

However, because the actual table-cell's vertical position is static, it is still affected by how the table is rendered, which brings us to section 17.6.2 on the collapsing border model.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
3

multiple rows - Try this css..

<style>
.absolute {
    left: 0;
    margin-top: -1px;
    border-right:0px;
    position: absolute;
}

@media screen and (-webkit-min-device-pixel-ratio:0)
{
.absolute {
    margin-top: 0px;
} 
} 
</style>

Chrome And Firefox Demo Screenshot.

enter image description here

Piyush Marvaniya
  • 2,496
  • 2
  • 16
  • 28
  • As already stated in the comments, `top: 0` fails when there are multiple rows, so it is not a good solution. – BoltClock Feb 27 '14 at 05:02
  • i have changes - Please see this above demos for multiple rows added – Piyush Marvaniya Feb 27 '14 at 05:55
  • OK. It looks like you've changed it to a negative margin instead, as well as using browser detection to remove the negative margin for browsers that don't need it. If the asker is comfortable with browser detection, so be it. – BoltClock Feb 27 '14 at 05:58
1

The reason this is happening is because you've specified the entry as absolute, meaning firefox's browser style where it sets the "top" css property to 1px is being used. If you want to avoid this you might be able to use a css reset file which blows away browser-specific default formatting.

As for your issue with setting top:0 resulting in the cells collapsing into each other, that is the correct behavior. Absolute renders in the space of the closest positioned CSS element. Think of it as if the element is no longer in its usual place in the DOM. If the two cells specified as absolute have the same closest positioned parent element (in this case the body) then they would both render relative to the same place with each having the top:0 property which means they would overlap.

I don't think either is wrong, you're just running into the (common) issue of browser styles.

Paarth
  • 9,687
  • 4
  • 27
  • 36
  • Of course, that is the correct behaviour of `top: 0`. If this can be solved by a browser reset, what is the reset? I have already reset margin and padding globally. – 1'' Feb 26 '14 at 03:36
  • Firefox does not arbitrarily set a default `top: 1px` anywhere in its default stylesheet. – BoltClock Feb 26 '14 at 04:28
  • @1'': I think the reset in this case refers to `top: 0`, which is not what you want. – BoltClock Feb 26 '14 at 05:08
  • @1'' There are css reset files floating around that are often included in sites. These reset files reset styling to a consistent default for almost everything so that you can specify exactly what you want in your personal CSS and it will be consistent across all browsers. Exactly what the reset.css files will cancel out depends on the file itself. This can also be called normalizing, which sometimes also includes sane defaults. – Paarth Feb 26 '14 at 05:21
  • @BoltClock That's not what I see. Here's my firefox inspect element interface: http://i.imgur.com/ClLVU1I.png The top entry showed up only after checking off the box for browser styles – Paarth Feb 26 '14 at 05:22
  • @Paarth: Ah yeah, that's what I'm seeing too. I guess what I meant to say is that it does not appear to be coming from the default UA stylesheet, because I cannot find it there. It appears to be the result of a rounding calculation instead - see my answer. – BoltClock Feb 26 '14 at 05:25
1

In short ,

There are two problem to me in this problem

a) The first problem is overlapping of left <th> with right <th>

The correct browser is one which overlapp the <th> because you are firstly giving the outer div margin-right:100px; the <th> with aboslute property should fit this area, but the extra border of 1px increase the width by 2px(left border + right border) .Hence the overlap is correct

b) The second problem is of top margin for the left element

It can be removed by adding

th{
 top:0px;
}

This is because of browser effect to html page

sanjeev
  • 4,405
  • 2
  • 19
  • 27