Closed RWDavid closed 1 month ago
@mfreed7 @lilles @tabatkins Do you know if this is a spec issue or an implementation issue or neither?
As far as I know, the current specification does not allow anchoring to fixed-positioned elements.
But this is indeed a common use case, such as the example in the floating UI.
https://github.com/w3c/csswg-drafts/assets/2784308/f58293b7-b41a-4530-ae58-e1e2f97f0566
The spec actually does permit anchoring to fixed-position elements. Although the exact wording is "absolutely positioned", both position: absolute
and position: fixed
are considered "absolute positioning".
This behavior works in Chrome, which you can see by replacing the position of the anchored element in the above test case from absolute
to fixed
.
So this is correct behavior, per spec. Your “anchee“ element is absolutely positioned inside the position:relative
containing block. Your "anchor" is fixed positioned, so its containing block is the ICB.
And https://drafts.csswg.org/css-anchor-position-1/#acceptable-anchor-element says:
Here, el is "anchor" and query el is "anchee". And this point isn't true, because "anchor" is absolutely positioned (fixed counts as absolutely positioned), and "anchee" comes after "anchor" in the layout tree, again because "anchee" is fixed positioned. So "anchor" is not an acceptable anchor element for "anchee". As mentioned above, change "anchee" to position:fixed
and you'll be good. Or remove position:relative
from the wrapper, so both have the same ICB containing block.
I am a little confused. Isn't my anchor element fixed positioned and isn't my positioned element absolutely positioned? And also, isn't my el is indeed placed before query el in the tree order?
Sorry, I got the anchor/anchee backwards in the first paragraph. Fixed now. The logic still holds. The anchor comes after the anchee in the layout tree. The DOM tree order is not material here.
@mfreed7 As far as the implementation in Chrome is concerned, is it possible to anchor to a fixed
element?
I simulated the effect of Floating UI by container query, but there is jitter when scrolling fast. https://codepen.io/yisi/pen/mdYExKX?editors=0100
It is possible to anchor to a fixed element if it is laid out before the other abs/fixed pos element.
E.g. if the fixedpos is captured by a containing block (that's not the ICB) with a transform or similar effect. Or referencing a another fixedpos element if they are both in the ICB.
Yes, this is working as intended. Your fixpos successfully finds the viewport as its containing block, while the abspos uses its parent div. In order for something to be a valid anchor, it has to be below the positioned element's CB in the box tree, but the viewport is considered "above" everything in the document.
Generally, a fixpos will only be able to serve as an anchor to other fixposes (and they'll have to follow it in DOM order). There's exceptions if an ancestor generates a fixpos containing block (like an ancestor with transform
), but that's a relatively rare case (it makes the element act like an abspos, so usually is something you avoid).
Your "anchor" is fixed positioned, so its containing block is the ICB.
@mfreed7 This is not true. The containing block of a fixed positioned box is the viewport (which does not scroll with the canvas), not the ICB (which does).
And this point isn't true, because "anchor" is absolutely positioned (fixed counts as absolutely positioned), and "anchee" comes after "anchor" in the layout tree, again because "anchee" is fixed positioned.
Being fixedpos doesn't change a box's position in the box tree.
Note, the fixedpos in the OP's testcase matches this condition here:
Either el is a descendant of query el’s containing block, or query el’s containing block is the initial containing block.
by virtue of being a descendant of it and the abspos's mutual parent, not by having a containing block of the ICB. If the fixedpos were a sibling of the relpos box then it would fail both conditions. I'm pretty sure that's not intended.
The prose in this section is just awfully hard to read; if nothing else this issue should stay open for editorial improvements.
I'm running into a similar issue with regards to "absolutely positioned" content.
See this broken example wherein:
position: fixed;
position: fixed;
, andposition: fixed;
AND on the #top-layer
Leading to the content not being positioned relative to the anchor:
You can work around this by positioning the parent differently, as seen here:
width
and height
position: fixed;
, andposition: fixed;
AND on the #top-layer
Leading to the content being positioned as expected:
Do we see this as "outside of the spec", something yet to be covered, an implementation issue? I've opened a Chromium bug in case it is the later...
@Westbrook Hm, that example definitely looks broken to me. Reproducing it myself, I find that it's the specific combination of (1) the container being abspos or fixpos, (2) the anchor being fixpos, and (3) the dialog being in the top layer, that break the positioning. Change any of those three, and it works successfully. This suggests a bug.
I think it's caused by the "acceptable anchor element" definition not really mentioning top layer stuff. I'm considering rewriting the relevant ordering conditions to the following:
* |possible anchor| is painted strictly before |positioned el|,
aka one of the following is true:
* |positioned el| is [=in a higher top layer=] than |possible anchor|
* Both elements are [=in the same top layer=]
but have different [=containing blocks=],
and |positioned el|'s [=containing block=]
is an ancestor of |possible anchor|'s [=containing block=]
in the [=containing block chain=],
aka one of the following:
* |positioned el|'s [=containing block=] is the viewport,
and |possible anchor|'s [=containing block=] isn't.
* |positioned el|'s [=containing block=] is the [=initial containing block=],
and |possible anchor|'s [=containing block=] is generated by an element,
* both elements' [=containing blocks=] are generated by elements,
and |positioned el|'s containing block
is an ancestor in the [=flat tree=]
to that of |possible anchor|'s [=containing block=].
* Both elements are [=in the same top layer=]
and have the same [=containing block=],
and are both [=absolutely positioned=],
and |possible anchor| is earlier in [=flat tree=] order
than |positioned el|.
* Both elements are [=in the same top layer=]
and have the same [=containing block=],
but |possible anchor| isn't [=absolutely positioned=].
(The constraints that aren't about relative ordering stay as they are.)
@lilles or @bfgeek , do these revised conditions sound correct to you? @fantasai, do these read better than the current text?
Lol, the bug you opened got fixed yesterday, and the example now works. Guess that's confirmation. ^_^
I am currently creating small test cases to solidify my understanding of the anchor positioning spec.
Here is one such test case that utilizes a
position: fixed
anchor and aposition: absolute
anchored element.It seems like the anchor is an acceptable anchor element, but the anchored element does not seem to accept that element as an anchor (at least on Chrome Canary version 127.0.6532.0).