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-anchor-position-1] Better handle an inset-area edge case when the default anchor element is partially or completely outside the containing block #9663

Closed
kizu opened this issue Nov 30, 2023 · 3 comments

Comments

@kizu
Copy link
Member

kizu commented Nov 30, 2023

I have a created a demo CodePen (viewable in the latest Chrome Canary with the experimental flags on): https://codepen.io/kizu/pen/zYemwKM?editors=1100

Here is a video of how things work right now:

Screen.Recording.2023-11-30.at.23.34.54.mp4

In it, we can see how inset-area behaves when the default anchor element is placed partially or completely outside its containing block.

I imagine, some quirks of how it is currently displayed might be implementation bugs/grey areas, but then I think maybe the spec could be adjusted to be more flexible to cover these cases?

To quote the current spec (https://drafts.csswg.org/css-anchor-position-1/#resolving-spans) (I did replace the ul with ol to number the lines):

The inset-area grid is conceptually a 3x3 grid, composed of four grid lines in each axis. In order:

The issue I see is the “in order” part, and how things work in the current Canary implementation when the lines are not, in fact, in order. When the default anchor partially intersects or entirely leaves its containing block (in all these examples I imagine it leaves into the “right”, or “end” direction), its lines' order messes up.

  • When the element partially leaves the containing block, the lines are ordered 1 2 4 3
  • When the element fully leaves the containing block, the lines are ordered 1 4 2 3

The current implementation seems to use the lines rather than areas, so the “center” would span the 2–3 lines, so it could go outside the containing block, and the all spans 1–4, so it would never leave the containing block.

I think this might be not what the authors could expect, and this behavior is not very useful for the cases when the elements leave the containing block.

My proposal would be: to make sure the lines always stay in the same order, and do this by stretching the containing block's lines to always fit the default anchor. To take the examples from the previous list:

  • When the element partially leaves the containing block, the lines are still 1 2 3 4, with the 3 & 4 lines being “merged” and being located at the anchor(end).
  • When the element fully leaves the containing block, the lines are, again, ordered 1 2 3 4, in the same way as above with 3 & 4 merged, and the 2 going outside the original containing block's bounds.

Now, there is a chance the “staying inside the containing block” behavior could be desirable (like keeping the tooltips in the viewport instead of them following the popover?), for this the best could be to introduce a separate property that would control this.

  1. By default, I think (but not strongly) when the element leaves its containing block, it stretches it, the first example in the CodePen above that only uses start/end/center currently behaves like this:

    A screenshot of a 3×3 grid where the element did leave the containing element on the left, with the grid stretching over the element itself.
  2. As an option, we could make the anchor's element's line never “leave” the containing block. In this case:

    • When the element partially leaves the containing block, the lines are still 1 2 3 4, with the 3 & 4 lines being “merged”, but located at the edge of the containing block.
    • When the element fully leaves the containing block, the lines are, again, ordered 1 2 3 4, but now the 2, 3 & 4 are merged.

    The second example in the CodePen above that has the “all” behaves this way (only in horizontal axis):

    A screenshot of a 1×3 grid where the element did leave the containing element on the left, with the grid being contained inside the containing block only.

We can see that right now we get either one behavior or another based on if we're using all keyword, or not, or maybe even some mixed weirdness like in the third example.

Making this edge case follow one of the ways with the lines always in order would be already an improvement, but I really think it would be the best to allow specifying this behavior: we'd want the grid to be always contained, or stretch over the combined area of an element and its containing block. Especially if we will decide to allow #9662 — in which case we will almost always want the “stretching” behavior.

@fantasai
Copy link
Collaborator

fantasai commented Dec 1, 2023

My assumption was that the tracks would indeed floor at zero, rather than scrambling. I hadn't thought about whether the tracks should attach to the anchor or the containing block. Tab and I agree it would make more sense to attach to the anchor (so like your first example) by default.

@tabatkins
Copy link
Member

So the issue was that, previously, inset-area was defined as something whose effects totally occurred at computed-value time, so we couldn't detect misordered lines and had to just let the chips fall where they may. Because we bias towards the startward insets (top left in English) when they're misordered, this happened to work reasonably when the anchor was off to the right or bottom of the CB (giving the results from your video), but did the wrong thing when it was above or to the left (we'd ignore the bottom/right, and only pay attention to the top/left: 0, so the positioned element would be trapped by the CB in those directions).

We just put up a new proposal for inset-area at #9598 (comment) which reverts that and makes inset-area a layout-time property, so we can detect misordered lines and have things work more naturally. We agree that the behavior should be the same regardless of what direction the anchor is outside of the CB, and it needs to be consistent with what happens as the anchor approaches the edge of the CB. We could either keep it stuck within the CB or keep it stuck to the anchor, and we think the most reasonable behavior is to make the "misordered" side be zero-size and stuck to the anchor. This is most consistent with the author's likely intent and the implicit intent of the default alignment, and what would happen if you used insets directly rather than inset-area.

That is, an inset-area: top / all; element, whose default anchor is way above the initial CB, will see an area-modified CB that's zero tall and flush with the top edge of the anchor. This is the same as if the author had written top: auto; bottom: anchor(top);.

(Note; %s in insets, margins, or width/height currently all resolve relative to the containing block size. With inset-area setting the containing block, they'd resolve relative to the inset-area-modified containing block, which is much more natural. It also tracks with the similar behavior of absposes whose CB is generated by a grid, where the grid positioning properties can adjust the containing block. If both occurred on one element, we'd nest the effects - grid first, then inset-area.)

@tabatkins
Copy link
Member

(The mentioned change is now committed, closing this issue.)

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

3 participants