Skip to content

[css-position-4] Ability to escape containment of other positioned elements #8588

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

Open
kizu opened this issue Mar 15, 2023 · 9 comments
Open

Comments

@kizu
Copy link
Member

kizu commented Mar 15, 2023

Disclaimer and additional links

I'm submitting my feedback following my experiments with the current implementation of anchor positioning in Chrome Canary.

I wrote an article about my experiments, but decided to fill most of my feedback as separate issues here.

A quick summary of related links:

On one side, I found an ability to wrap some stuff into an element with position: relative and this isolate all the anchors inside to be a useful one, on the other — I found this to be very limiting.

I'm not sure if something like that is planned/already considered in the specs, but what I would love is to be able to change that positioned context separately from the anchor-name. Maybe using a container-name or something similar?

Basically, I would want to be able to tell an element “regardless of where you're placed in the tree, I want you to emerge upward up to a certain container, and only then look up for your anchor-names.” This would allow using global popovers, without a fear of them being constrained by some random position: relative that a parent could get.

This is very similar to the position: sticky problem, which often is limited by its context, or even position: fixed that often can get blocked by its stacking context having something like a transform applied. So it would be really nice for an absolutely positioned element to be able to “escape” its stacking/positioning context.

When I was initially thinking of anchor positioning, this was one of the first things I always wanted to be able to do in CSS — ability to skip some of the parents with position: relative or choose one of the parents explicitly as the context for my element, rather than relying on the implicitly defined contexts.

@tabatkins
Copy link
Member

How much of this is addressed by just using position:fixed on your element instead? Then it's global, ignoring any relpos ancestors (but still being affected by things like transform). (The Popover API, by putting things in the top layer, ends up avoiding transforms as well.)

Or do you specifically need the ability to scope anchor names, just to a different ancestor than what's implied by the abspos containing block?

@kizu
Copy link
Member Author

kizu commented Mar 15, 2023

I did not experiment with fixed position yet — did a quick test, and it is almost what I would want: https://codepen.io/kizu/pen/PodeOMx?editors=1100

The initial state seems to be what I would like to have — the element escapes its parent with the position: relative, but the issue is when we start scrolling:

Screen.Recording.2023-03-15.at.18.13.47.mov

Because it has “fixed” position, it just stays in the initial position as if the scroll did not happen.

Again, I did not yet play with the anchor-scroll, so not sure if it could be used to solve this? If not, then fixed does not solve my issue, as what I would want is for my element to be in the global scope, but behave like absolute and not fixed.

@kizu
Copy link
Member Author

kizu commented Mar 15, 2023

Update! Quickly also tested the anchor-scroll, and it seems very promising: https://codepen.io/kizu/pen/eYLryLE?editors=1100

I'm not entirely sure how/why it works the way it works in combination with position: fixed, and it works regardless of which anchor I provide (either --a or --b seem to work), but for this exact case this actually works! Very very cool!

Now, I'm not super sure what could be the difference between what I'm proposing and this workaround — I would need to do a bit more testing.

From the top of my head — potentially, the rules for the anchor acceptance could be different for a fixed element and an element inside a certain scope maybe?

@kizu
Copy link
Member Author

kizu commented Mar 15, 2023

Ok, another update: https://codepen.io/kizu/pen/eYLryLE?editors=1100

Basically, I think I was correct in my last assessment — I added an extra .outer-element to the example above, as well as an extra wrapper.

What I would want in this example — to inner element to only skip the inner .wrapper, but not go outside of the top-most wrapper, allowing an element that is outside of everything to still being able to target that absolutely-positioned element.

I think that would be maybe the main difference I can think of right now between the position: fixed behavior, where we lose an ability to attach anything extra to out elements, and if we could “skip” certain wrappers, still being assigned to some inner layer. Maybe there would be other aspects that I'm missing and which could be different — would need to find time to explore this more.

Sorry for the spam :)

@tabatkins
Copy link
Member

From the top of my head — potentially, the rules for the anchor acceptance could be different for a fixed element and an element inside a certain scope maybe?

Correct. The anchor has to be fully laid out before we start laying out the positioned element, and that is ensured by the "acceptable anchor" conditions. If the positioned element is fixpos, tho, that pretty much forces it to be laid out after the entire rest of the page, so the conditions are satisfied fairly trivially.

I'm not entirely sure how/why [anchor-scroll] works the way it works in combination with position: fixed, and it works regardless of which anchor I provide (either --a or --b seem to work)

In short, anchor-scroll walks up the CB chain of both the anchor and the positioned element, noting any scrollers it encounters, and then takes into account the scroll offsets of each of them to shift the positioned element so it continues to track the anchor correctly. A fixpos isn't special here; it just happens to use the initial containing block (which is above all scrollers in the page), so it'll accumulate offsets from all scrollable ancestors of the anchor all the way to the root.

What I would want in this example — to inner element to only skip the inner .wrapper, but not go outside of the top-most wrapper, allowing an element that is outside of everything to still being able to target that absolutely-positioned element.

This would be a more general abspos alteration, unrelated (directly, at least) to anchor positioning: reparenting the abspos in the box tree to a given ancestor containing block, rather than just choosing between the nearest (for abspos) or the initial containing block (for fixpos).

So, currently out of scope for Anchor Positioning, but within reason as a future feature for the Positioning spec.

@kizu
Copy link
Member Author

kizu commented Mar 15, 2023

So, currently out of scope for Anchor Positioning, but within reason as a future feature for the Positioning spec.

Yep, agree that this can be applied more generally… speaking of which — omg how I would want to be able to “skip elements” for sticky positioning! It is currently very finicky to use, with extra wrappers breaking things, I think if we would consider this a wider feature, then for sticky positioning this would be much more helpful than for the more rare edge-cases that I'm thinking of for the absolute positioning.

@kizu
Copy link
Member Author

kizu commented Mar 21, 2023

Another thing that I found impossible to implement with anchor positioning, and for which an ability to escape the containment could be used — for replicating the behavior of the Popover API. The popovers from it can properly escape their context, regardless of any position: relative on them or maybe even some strict contain.

Anchored elements do not have this feature, as even fixed elements behave just like our good old fixed ones, making it very easy to have a wrapper that would restrict what we could do with them, leading to the necessity to use JS to portal them to the end of the body manually.

For popovers-related things we could use the Popover API, however I'd argue that there could be a lot of potential usage for anchored decorations that would also need to be able to escape their containers in the same way.

I would also argue that ideally, we should design CSS & HTML in a way where any native HTML behavior that relates to layout, positioning and any visuals must be possible to re-create with CSS. Otherwise, for various cases, developers would be lead with two options: either using JS for presentational needs, or misuse the HTML API that provides the functionality they need (see all the logic on checkboxes, :target etc). And having an ability to re-create the new popovers behavior with just CSS is something that fits that idea.

@tabatkins
Copy link
Member

Yeah, the "recreate popover-ish behavior using plain CSS" discussion has been had - currently the opinion of impls is that exposing top layer directly (not controlled by the UA in a dismissable fashion) isn't something they want to do.

But the actual box-tree reparenting part of it is indeed super useful, so even if we can't reparent into a top layer, reparenting into the root (thus escaping all ancestor traps like transform) would indeed be very useful. I believe it's a separate concern tho, but indeed becomes more relevant with Anchor Positioning since a dependable fixpos becomes so much more useful.

@tabatkins tabatkins changed the title [css-anchor-1] Ability to escape containment of other positioned elements [css-position-4] Ability to escape containment of other positioned elements Sep 1, 2023
@tabatkins
Copy link
Member

(Re-tagging this to be against Position 4. The ability to more explicitly select a containing block, rather than just deciding between the nearest ancestor that establishes an abspos containing block and the viewport, is a general issue for Positioning, as it affects your containing block and what your inset properties refer to. Its effect on Anchor Positioning is similar but definitely not Anchor Positioning-specific.)

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

2 participants