Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-position] Interoperability issues with absolute positioning #3952

Open
jfkthame opened this issue May 22, 2019 · 5 comments
Open

[css-position] Interoperability issues with absolute positioning #3952

jfkthame opened this issue May 22, 2019 · 5 comments

Comments

@jfkthame
Copy link
Contributor

https://drafts.csswg.org/css-position-3/#abs-pos

I'm seeing some interop issues related to position:absolute, and it's unclear to me whether the spec gives clear guidance as to what the correct behavior should be. (It's entirely possible I haven't looked in the right place, though.)

My questions relate to the default placement of an abs-pos element with display:block, where the element occurs at the beginning (more-or-less, see below) of a line; the issue is whether the abs-pos element lines up with the top of the containing line, or drops below it.

Consider first a simple example:

data:text/html,<!doctype html><p><div style="position:absolute">X</div>foo

In this case Safari, Chrome, Firefox all agree that the abs-pos "X" overprints the beginning of the in-flow text "foo". AIUI, this is because at the point where the abs-pos element occurs, the current line is empty, so the block is aligned with the top of the containing line.

However, if we change the containing block element to a bulleted list item:

data:text/html,<!doctype html><ul><li><div style="position:absolute">X</div>foo

Safari and Chrome now drop the "X" down below the text "foo", whereas in Firefox it still overprints. Which behavior is correct?

(ISTM the Firefox behavior here makes sense: the bullet is entirely outside the line box, so does not affect the placement of the abs-pos element within it.)

A further discrepancy occurs in the presence of borders/margins/padding. For comparison, consider an example where the abs-pos element has display:inline:

data:text/html,<!doctype html><p><span style="border-left:10px solid blue"><span style="position:absolute">X</span>foo

Here, the browsers all agree that the inline abs-pos "X" appears after the left border of the containing span, so it overprints the beginning of "foo".

But if we add display:block to the abs-pos span:

data:text/html,<!doctype html><p><span style="border-left:10px solid blue"><span style="position:absolute;display:block">X</span>foo

then Safari and Chrome let the "X" move back to the beginning of the line, so it overprints the blue border, whereas Firefox considers that by the time the "X" occurs, the line is non-empty and so it drops below. Which behavior is correct?

(Here again I think the Firefox behavior makes sense; comparing the previous example where the abs-pos element has display:inline, we can see that its "anchor" position is clearly not at the start of the line, so it seems correct that it drops below. OTOH, Firefox also does this if the containing span only has a right border, which is clearly a bug.)

A left margin or padding on the enclosing span yields similar results; see https://bugzilla.mozilla.org/show_bug.cgi?id=1553418 for a more extensive testcase.

@fantasai
Copy link
Collaborator

fantasai commented May 22, 2019

Afaict from your description, Firefox's behavior is correct.

In the first case, adding an outside-positioned marker box should have no effect on the layout of the contents of a block, so switching between 'list-item' and 'block' should not affect the abspos position.

Wrt the second case, the static position is calculated from the "hypothetical position" of the box if its 'position' value had been 'static'. When you add 'display: block' to that, then that position changes because if it were a block, it would move to the next line. You can see this by removing 'position: absolute'. The spec allows the UA to "make a guess" as to the probable location of the box, so technically Chrome and Safari are spec-compliant, but Firefox is more correct. Afaict.

The active spec for abspos, btw, is CSS2: css-position is not known to be reliable for anything other than 'position: sticky'. https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width

@hrj
Copy link

hrj commented Sep 19, 2019

the static position is calculated from the "hypothetical position" of the box if its 'position' value had been 'static'.

Am I right in my understanding that when the position is assumed to be static it could lead to a completely different box tree? It might cause new anonymous boxes to be created, for example.

This makes the spec very ambiguous and the implementation, if at all feasible, to be very complex.

@MatsPalmgren
Copy link

@hrj No, it does not affect box construction, only layout position/size.

@hrj
Copy link

hrj commented Sep 20, 2019

@MatsPalmgren I am a n00b so please help me understand. Consider this example:

<div id="parent">
  Some text
  <div id="child" style="position:absolute;  display: inline">

Applying section 9.7 of CSS 2 to child, position:absolute forces the computed value of display to block. Because of which an anon block box is needed around "some text". The children participate in a block formatting context.

However, when position is assumed static, then display computes to inline and then the anon block box is not needed because parent has only inline children. Also, parent now establishes an inline formatting context.

Is that correct?

@faceless2
Copy link

faceless2 commented Sep 20, 2019

The anon block box you refer to is what I would think of as a linebox. That's still needed, because there is inline content to position on the line. The lines are then stacked one after the other down the page, as if they were block boxes.

The only impact display has on an absolutely positioned box is its initial (or "static") position. If it's display: inline, as it is here, it's positioned where an inline element would be in the same context: immediately after the "Some text" on the same line. If it's display: block, it's positioned where a block element would be in the same context: on the line below "Some text" at the left edge of "parent".

And if you set left and top on the child, this static position is overridden, and the value of display has no effect at all.

Both cases result in an identical box tree. CSS 2 section 9.2.1.1 refers to an algorithm for rearranging the box tree if an inline element contains a block, but this only applies to in-flow children; absolutely positioned children are transparent to this algorithm.

(I should add that there is some ambiguity when the child is inline, and it's static position is where a line soft-wraps. Is it positioned at the end of the first line or the start of the second? This is what's being tested by http://web-platform-tests.live/css/css-text/line-breaking/line-breaking-019.html)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants