Skip to content

[css-contain] Can we allow absolutely positioned elements to escape a container? #10102

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

Closed
mirisuzanne opened this issue Mar 20, 2024 · 10 comments

Comments

@mirisuzanne
Copy link
Contributor

I'm splitting this out from #10040, where we resolved that anchor-name is able to escape containment. That helps authors position elements in relation to contained anchors. But it doesn't help with the inverse: absolutely positioned elements inside a container cannot be anchored to anything outside the container.

This mirrors a common footgun with container queries. The container (layout containment) generates a fixed positioning context, so position-fixed elements are fixed to the container rather than the viewport.

If there is any way to loosen that requirement for container queries, it would remove the footgun and also allow more fluid interaction between container queries and anchor positioning.

I'm not entirely clear why this fixed-positioning context restriction is useful for container query implementations. I would have expected the (already resolved) counter example to be more problematic - since generally we don't want external layouts relying on container internals. In this case we only want internal layout to rely on external context - which is already the case. But maybe my mental model is wrong here?

@tabatkins
Copy link
Member

Given that top layer lets us do this already, I assume that the core functionality of "move this element around in the box tree" is at least feasible. What I'm not clear on is if there are complications that make it difficult to go anywhere between "use the normal CB" and "use the topmost possible CB".

I'm not entirely clear why this fixed-positioning context restriction is useful for container query implementations.

I think it's just because of static positioning - figuring out the static position requires doing layout on the subtree, and that would defeat the layout-containment optimization. We'd have to zero out the static position if we did something with this. (Which isn't a problem for anchor positioning, obviously.)

I think that's similarly why things like transforms create fixpos containing blocks - if the static position isn't transformed, then it's just a nonsense position with no relation to anything, but if it is transformed, then it could become an unaligned non-rectangle wrt the fixpos element, which isn't meaningful for static positioning either.

So yeah, in all cases I think it's fine to let an element move its CB higher in the tree, so long as it loses its static position in the process (just goes in the start/start corner or something instead).

@mirisuzanne
Copy link
Contributor Author

I think that would be an acceptable tradeoff in most cases.

@frivoal
Copy link
Collaborator

frivoal commented May 31, 2024

Don't we also have an issue if we let abspos escape their containment that they could overflow some ancestor, create scrollbars, and thereby affect the layout of the rest of the page?

@tabatkins
Copy link
Member

Right, that would potentially be one of the «complications that make it difficult to go anywhere between "use the normal CB" and "use the topmost possible CB"»

@dbaron
Copy link
Member

dbaron commented Jul 8, 2024

A side comment, but I think for transforms the difference is also semantic. If you're rotating the "contents of an element", how does that affect the position of something in that element's subtree that's actually positioned relative to something outside of the subtree? Does it escape the transform? Does it instead add up the translations out to what it's relative to and then subtract back in to the transformed element, and then transform as though it had that translation from the transformed element?

On the main issue here: the underlying request here seems reasonable to me, though, as long as it's not anchoring to something that's inside a container that the positioned thing is outside. It's less clear to me what is the right way to move definitions/terms around to get that result.

@bfgeek
Copy link

bfgeek commented Jul 8, 2024

I've filed #10544 which tries to solve this issue (and others) slightly more generally.

@andrewhodel
Copy link

That doesn't work.

When you add container-type: inline-size you make the element a containing block according to https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block.

According to https://developer.mozilla.org/en-US/docs/Web/CSS/position, any element with position: absolute uses the bounds of the containing block it is a child of.

If you change this, you need to remove item 4 from the specification described at https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block

Identifying the containing block
The process for identifying the containing block depends entirely on the value of the element's position property:

  1. If the position property is static, relative, or sticky, the containing block is formed by the edge of the content box of the nearest ancestor element that is either a block container (such as an inline-block, block, or list-item element) or establishes a formatting context (such as a table container, flex container, grid container, or the block container itself).
  2. If the position property is absolute, the containing block is formed by the edge of the padding box of the nearest ancestor element that has a position value other than static (fixed, absolute, relative, or sticky).
  3. If the position property is fixed, the containing block is established by the viewport (in the case of continuous media) or the page area (in the case of paged media).
  4. If the position property is absolute or fixed, the containing block may also be formed by the edge of the padding box of the nearest ancestor element that has any of the following:
    A filter, backdrop-filter, transform, or perspective value other than none.
    A contain value of layout, paint, strict or content (e.g. contain: paint;).
    A container-type value other than normal.
    A will-change value containing a property for which a non-initial value would form a containing block (e.g. filter or transform).
    A content-visibility value of auto.

You can also mitigate this problem by using position: relative in the element that is to be the containing block.

It broke in Chrome with the latest release - https://issues.chromium.org/issues/369781727

@andrewhodel
Copy link

The specification that MDN links to explains the same result

https://www.w3.org/TR/css-position-3/#intro

Absolute positioning, which ignores normal layout entirely, pulling the element out of flow and positioning it relative to its containing block with no regard for other content.

The inner element position applies to the containing block when position is absolute.

https://www.w3.org/TR/css-contain-3/#containment-types

3.1 Inline-Size containment

Giving an element inline-size containment applies size containment to the inline-axis sizing of its principal box.

The outer element is a containing block when container is set to inline-size.

@mirisuzanne
Copy link
Contributor Author

Yes, it's true that the specification is out of date, and needs to be updated. We resolved on that change previously, and the relevant issue is labeled appropriately needs edits. This is how the process works. I believe this issue can be closed as resolved.

@andrewhodel
Copy link

When you set container-type: inline-size you make the element a containing block.

There is no containment specification because containment is arranged based on the order of the containing blocks.

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

No branches or pull requests

6 participants