w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 666 forks source link

[css-position-3] Containing block of dialog fixed position children #8040

Closed rwlbuis closed 4 months ago

rwlbuis commented 2 years ago

I wonder what the cb should be of the fixed positioned dialog child:

<html>
....
<div style="transform:...">
  <dialog> <!-- in top layer -->
    <div style="position:fixed">
....

If this test is valid then the fixed positioned dialog child'cb is html aka viewport: https://wpt.fyi/results/html/semantics/interactive-elements/the-dialog-element/top-layer-stacking.html?label=experimental&label=master&aligned

I have heard some opinions though that the dialog itself should be the cb.

I can't really conclude from the spec what the cb should be, for one thing what should qualify something to be a fixed positioning containing block seems not specified in one location/spec. Is there something I am missing in the spec and/or what do people think should be the cb in the example?

Loirooriol commented 2 years ago

If I get it right, https://fullscreen.spec.whatwg.org/#new-stacking-layer says

It is rendered as an atomic unit as if it were a sibling of its root.

which seems to imply the dialog is reparented in the box tree. Then the transformed div is not an ancestor of the positioned div in the box tree. And this is a requirement https://drafts.csswg.org/css-position/#fixed-cb

The containing block is established by the nearest ancestor box that establishes an fixed positioning containing block

So the transformed div should not be the containing block.

Instead, I guess the containing block should be the viewport, since the dialog doesn't have a transform or something that makes it establish a fixed positioning containing block.

Alternatively, <dialog> could automagically establish a fixed positioning containing block if that's considered to be better behavior.

rwlbuis commented 2 years ago

@tabatkins WDYT?

tabatkins commented 2 years ago

Right, this probably does still need a little more clarification, but anything moving to the top layer is reparented for rendering purposes. Everything Oriol said is correct. Assuming the dialog itself isn't doing anything, its fixpos descendants will just see the ICB as normal.

emilio commented 2 years ago

I think it probably makes sense to make top layer elements a containing block for all descendants like transform / etc do, though...

smfr commented 2 years ago

So how should the following behave:

<dialog style="position:absolute"> <!--- after showModal --->
  <div style="position:fixed"></div>
</dialog>

With the proposal (top layer is containing block for fixed) then the position:fixed will scroll with the document.

tabatkins commented 1 year ago

@emilio Why do you think that's a better behavior than letting fixpos "work normally" in the top layer? Top layer just moves where in the order it paints, it doesn't create any essential separate painting contexts like transform/etc does.

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [css-position-3] Containing block of dialog fixed position children, and agreed to the following:

The full IRC log of that discussion <TabAtkins> smfr: If you have fixpos inside a dialog, and dialog is on top layer, what's the containing block of the fixpos?
<TabAtkins> smfr: Dialog can be abspos *or* fixpos itself
<TabAtkins> smfr: If dialog is abspos, what's the fixpos behavior when the user scrolls the document?
<TabAtkins> smfr: If dialog has a transformed ancestor, does that affect the containing block for the fixpos descendent?
<TabAtkins> smfr: Both of these are impacted by whether the dialog itself is a CB for the fixpos
<Rossen_> q?
<TabAtkins> smfr: The top layer is kinda viewport-like
<fantasai> chrishtr: Is there interop on this or not?
<fantasai> scribe+
<fantasai> emilio: I think we don't enforce dialog to be a fixedpos dialog, but we want to
<fantasai> emilio: the containing block chain is pretty weird otherwise
<chrishtr> I don't think chromium makes dialog a containing block either
<fantasai> emilio: or at least we need to spec that any fixedpos inside the top layer are also in the top layer
<fantasai> emilio: otherwise, breaks the assumption that the containing block ... the in-flow content is laid out before the fixedpos
<fantasai> emilio: so unclear how the hypothetical positoins work if you don't at least define that they go in the top layer as well
<fantasai> emilio: in that case might want to make the dialog a containing block as well, much easier
<fantasai> emilio: don't see the point to have a fixedpos and not want it in teh top layer
<TabAtkins> fantasai: I think making it in the top laye rmakes sense
<TabAtkins> fantasai: I can imagine that you might not want the dialog to be a fixpos CB
<Rossen_> ack fantasai
<TabAtkins> fantasai: because you might actually want something outside the dialog wrt the viewport, while ahving the dialog open. can def imagine that
<TabAtkins> emilio: At that point we've given a special way to put something in the top layer...
<fantasai> TabAtkins: what's the concern about puttin gin the top layer? dialog is already there
<TabAtkins> emilio: It might be fine, I need to think more about ti
<TabAtkins> chrishtr: Seems like it'll be okay to me
<TabAtkins> chrishtr: The fixpos goes in the top layer, and if the dialog scrolls the fixpos won't scroll with it
<TabAtkins> chrishtr: That seems doable and not problematic; I assume that's how browsers would automatically work
<TabAtkins> smfr: What do you mean by "in the top layer"?
<TabAtkins> chrishtr: z-order
<TabAtkins> smfr: This is about CB, not painting order
<TabAtkins> chrishtr: Right, if the fixpos has a transformed ancestor within the dialog, that'll trap the fixpos as normal. If the transformed ancestor is outside the dialog, it won't affect it - it's specified as reparenting in the rendering tree.
<TabAtkins> smfr: So if you ahve a nested set of position:fixed do they all go in the top layer?
<masonf> q?
<TabAtkins> chrishtr: top layer is just reparenting and stacking context, it doesn't affect the CB
<TabAtkins> chrishtr: Maybe we should make some demos and come back to the group
<TabAtkins> Rossen_: sounds reasonable
<TabAtkins> Rossen_: k let's collect some examples in the issue
<TabAtkins> emilio: I think there's consensus that a transformed ancestor of the dialog isn't a CB for the fixpos, due to the reparenting.
<TabAtkins> proposed resolution: Clarify that due to the box-tree reparenting, an ancestor outside the dialog can't be a fixpos CB for children of the dialog
<emilio> +1
<fantasai> wfm
<fantasai> s/children/descendants/
<masonf> +1
<chrishtr> +1
<TabAtkins> RESOLVED: Clarify that due to the box-tree reparenting, an ancestor outside the dialog can't be a fixpos CB for children of the dialog
<TabAtkins> (Still unresolved: what exactly the CB of a fixpos descendant of the dialog is.)
chrishtr commented 1 year ago

Firefox, Safari and Chrome all have interop on this example, which has a fixed-pos element below a dialog with abs-pos. So I think we should keep the spec as is and not make <dialog> a container for fixed-pos descendants.

tnikkel commented 1 year ago

Firefox, Safari and Chrome all have interop on this example, which has a fixed-pos element below a dialog with abs-pos. So I think we should keep the spec as is and not make <dialog> a container for fixed-pos descendants.

If you add a transformed div containing the dialog in this testcase then Firefox, Safari, and Chrome all have different renderings.

emilio commented 1 year ago

@emilio Why do you think that's a better behavior than letting fixpos "work normally" in the top layer? Top layer just moves where in the order it paints, it doesn't create any essential separate painting contexts like transform/etc does.

It also changes the containing block of the elements in a way that it escapes transformed ancestors etc.

emilio commented 1 year ago

It also causes layout ordering issues in some cases. E.g., if you have a top layer with a regular fixed-pos inside, what is the hypothetical position of that fixed-pos?

emilio commented 1 year ago

I think the two realistic options are:

Otherwise you have layout cycles (since the fixed pos hypothetical position depends on the top layer being already laid out, but the top layer could be in a regular fixed pos too).

The former has a risk of making the internal top layer list that the HTML spec uses out of sync with the CSS top layer, so I have a preference for the later.

chrishtr commented 9 months ago

Otherwise you have layout cycles (since the fixed pos hypothetical position depends on the top layer being already laid out, but the top layer could be in a regular fixed pos too).

I don't see how the top layer can "be in a regular fixed pos". If an element has an ancestor that is position:fixed, then while the element is in the top layer, that position:fixed element does not affect the element's layout. The top layer reparents the element in the layout tree.

In other words, the element gets put in a different place in the layout tree, and then its layout, containing block and so on is determined according to that adjusted tree, with the usual rules.

css-meeting-bot commented 9 months ago

The CSS Working Group just discussed [css-position-3] Containing block of dialog fixed position children.

The full IRC log of that discussion <fantasai> emilio: What happens if you have a fixedpos inside an abspos top layer?
<fantasai> emilio: Normally fixedpos has a different containing block, the viewport, and fixedpos works normally
<fantasai> emilio: but making stuff escape the top layer element is very weird
<fantasai> emilio: So first question is, should fixedpos be in the top layer
<fantasai> emilio: it's a controllable top-layer thing, which is weird
<fantasai> emilio: if it should not, then that breaks the layout ordering of the elements
<fantasai> emilio: to layout fixedpos, you want to layout top layer element first, but that's usually the last thing you lay out
<fantasai> emilio: so different ways to address this
<fantasai> 1. Do nothing. But if you have a transform between fixedpos and top layer, everyone behaves differently
<fantasai> emilio: Simplest would be making toplayer also fixedpos containing block (as if adding a transform)
<fantasai> emilio: that makes sure that nothing escapes the top layer
<fantasai> s/1./emilio: 1./
<fantasai> emilio: I tried that but it broke some stuff. I think WebKit used to do this in the past, so might still be doable?
<fantasai> emilio: There are some interesting cyclic issues, because toplayer escapes the normal containing block rules
<fantasai> emilio: it gets hauled up to viewport even if transformed ancestor
<fantasai> emilio: but its static position needs to be known before laying out
<fantasai> emilio: but fixedpos can be in the old place in the DOM
<fantasai> emilio: so some interesting cases there
<fantasai> emilio: toplayer can be anywhere in tree, doesn't need to respect normal CB rules
<fantasai> emilio: could end up laid out in the wrong order
<fantasai> emilio: I have a slight preference to make toplayer a fixedpos containing block, but that's probably not doable
<chrishtr> q+
<fantasai> emilio: so what do we do? do we promote fixedpos to toplayer or something else?
<TabAtkins> q+
<fantasai> oriol: I just noticed the problem in Firefox, but haven't looked in detail
<TabAtkins> fantasai: there's some concepts here i'm not super familiar with
<astearns> ack fantasai
<TabAtkins> fantasai: so the top layer is, you pull it out of normal stacking contexts, it goes at top of z-order
<TabAtkins> fantasai: from layout perspective, it's an abspos element, it has a static position in the rest of the document - does it know where that is?
<TabAtkins> fantasai: so layout-wise it might be able to look at that static position
<TabAtkins> fantasai: and then you have a fixpos inside the top-layer'd element
<TabAtkins> fantasai: and so q is what you do with the fixpos
<TabAtkins> emilio: yes
<TabAtkins> fantasai: what makes sense to me is the static position of the fixpos is wherever it would be in inside the top-layer'd element
<TabAtkins> fantasai: and then the top layer element and its decendants, including the fixpos, are forming almost thier own document
<TabAtkins> fantasai: the fixpos will be in that top layer, then
<TabAtkins> fantasai: multiple fixpos will sort by zindex normally, but won't leave their top layer slot
<TabAtkins> emilio: i dont' think that's what browsers do now
<TabAtkins> emilio: i think main issue is that if they are in top layer
<TabAtkins> emilio: then i think it's fine
<TabAtkins> emilio: but if the're not, the way you lay things out may mean the fixpos is laid out before the staticpos of the top layer'd element
<TabAtkins> fantasai: but i'm proposing that they be in the top layer
<TabAtkins> fantasai: from the author's perspective, you have a dialog, kinda like a sub window. if it raises to the top layer, its contents should come with
<TabAtkins> emilio: hm possibly. we havent' done a lot of allowing other thins that isn't explicitly the top layer to be in the top layer
<TabAtkins> emilio: absposes dont' ahve the issue since they're contained within the top layer'd element
<TabAtkins> fantasai: but so is a fixpos
<TabAtkins> emilio: the containing block of an abspos *is* the top layer
<TabAtkins> dbaron: yes, containing block isn't just layout concpet, it also affects painting and z-order
<TabAtkins> emilio: so I think that idea is fine, browsers just don't do it currently
<dbaron> s/yes, //
<TabAtkins> emilio: oriol's testcase was a transformed modal on top of the top layer
<chrishtr> containing block doesn't affect paint order....
<TabAtkins> emilio: which would normally contain it, but if it's in top layer it's not
<TabAtkins> emilio: but i think promoting the fixpos to the top layer fixes the problem
<oriol> q+
<TabAtkins> fantasai: if you have a doc whose root element is abspos, and it has a fixpos child, how we lay that out seems to make sense here too
<astearns> ack chrishtr
<dbaron> https://drafts.csswg.org/css-position-4/#document-top-layer
<TabAtkins> chrishtr: so the way toplayer is defined, when an element enters the top layer it's reparented in the layout tree, under the root element of the document
<TabAtkins> chrishtr: its containing block is now determined by that tree
<TabAtkins> chrishtr: so the fixpos that is a child of a top layer'd element will have the root as its CB and laid out accordingly
<TabAtkins> fantasai: fixpos doesn't use root element as CB, it uses viewport
<dbaron> or really all of https://drafts.csswg.org/css-position-4/#top-layer
<TabAtkins> emilio: that's all true per spec, but i don't think impls do that yet
<TabAtkins> chrishtr: it shoul be what chromium does, and it doesn't cause issues
<TabAtkins> emilio: I think in gecko there's osme interesting order issues, i'll dig them up
<TabAtkins> emilio: I don't think we're going to find a lot of use-cases
<TabAtkins> emilio: i think there's still some layout ordering issues where, depending on how the DOM order is for abspos vs fixpos...
<TabAtkins> emilio: you might lay out one of them without laying out the thing that contains it
<TabAtkins> emilio: I have a test case which shows it
<TabAtkins> chrishtr: okay. as far as I can tell it's no different from an abspos with a fixpos under it and that works fine
<astearns> ack TabAtkins
<fantasai> TabAtkins: Right now, if you have abspos that contains fixedpos, the fixedpos is laid out after the rest of the document. First abspos, then fixedpos.
<fantasai> TabAtkins: if the abspos is put into top layer, then it's laid out after the rest of the document including fixedpos
<fantasai> TabAtkins: so Elika's suggestion that we put the fixedpos into the top layer slot makes sense
<TabAtkins> fantasai: and you should do that with the abspos children of the top layer'd element anyway
<TabAtkins> TabAtkins: yeah that's automatic, abspos is always a CB for its abspos children
<fantasai> TabAtkins: Let's have a concrete example
<astearns> ack oriol
<TabAtkins> TabAtkins: We're talking in circles, let's do a concrete example in the issue
<astearns> Zakim: close queue
<astearns> Zakim, close queue
<Zakim> ok, astearns, the speaker queue is closed
<dbaron> oriol: should these elements being promoted into the top layer be in the HTML spec's explicit list of elements in the top layer?
<fantasai> oriol: are we adding to toplayer list or ...?
<dbaron> fantasai: no
<fantasai> fantasai: it doesn't get its own toplayer, it's associated with the abspos
<fantasai> fantasai: descendants of the toplayer should be laid out and stacked relative to each other just as if they were the only contents of the document
<fantasai> ...
<fantasai> iank_: toplayer absposes get inserted into the tree ... but, that's just a side-effect
<fantasai> chrishtr: if you put 'position: absolute' on HTML element
<fantasai> chrishtr: it just works afaict
<fantasai> emilio: I think we don't share the same list for toplayer items as non-toplayer items for a reason, I need to look into it
<fantasai> astearns: OK, let's take it back to the issue
<fantasai> fantasai: I think the proposal is basically, the toplayer element and its descendants are all laid out and stacked exactly as if they are the sole contents of the document
<fantasai> fantasai: and this is placed over the backdrop as part of a single toplayer layer
<astearns> zakim, open queue
<Zakim> ok, astearns, the speaker queue is open
chrishtr commented 6 months ago

If you add a transformed div containing the dialog in this testcase then Firefox, Safari, and Chrome all have different renderings.

Chrome renders this example correctly (which has a transform) according to the current specification. Firefox doesn't seem to render either this or the earlier one right, not sure why.

chrishtr commented 6 months ago

It also changes the containing block of the elements in a way that it escapes transformed ancestors etc.

Yes, it does, but that is on purpose and a good thing, because it lets the top layer render on top and outside of its parented boxes (by reparenting the boxes in the layout tree. I think that is well-defined and makes sense because the top layer is a special stacking context on top of and outside of other page contents.

It also causes layout ordering issues in some cases. E.g., if you have a top layer with a regular fixed-pos inside, what is the hypothetical position of that fixed-pos?

The containing block of that fixed position element's box is the containing box that is a container for fixed position (not the containing DOM element). So if there was a transformed element ancestor box of it within the top layer then the fixed position element would be contained by it. Otherwise it would be contained by the root (aka LayoutView in Chromium, aka viewport).

chrishtr commented 6 months ago

Agenda+ to propose closing this issue as no change to specification.

emilio commented 6 months ago

I'm ok with that as long as we fix https://github.com/w3c/csswg-drafts/issues/9939 too :)

chrishtr commented 6 months ago

I'm ok with that as long as we fix #9939 too :)

Agreed!

css-meeting-bot commented 4 months ago

The CSS Working Group just discussed [css-position-3] Containing block of dialog fixed position children, and agreed to the following:

The full IRC log of that discussion <flackr> Scribenick: flackr
<flackr> chrishtr: I propose closing this no change to specification
<flackr> chrishtr: We resolved 9939 at the F2F, having to do with static position. Given that, emilio mentioned he's good with this resolution given that change.
<flackr> chrishtr: there's no changes for fixed pos elements in top layer, they'll continue to be according to their position in the layout tree as repositioned
<flackr> Rossen7: any objections?
<flackr> RESOLVED: No change to specification