w3c / csswg-drafts

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

[css-anchor-position-1] Interaction with `anchor-center` and scrolling #9223

Open xiaochengh opened 1 year ago

xiaochengh commented 1 year ago

(Split off from https://github.com/w3c/csswg-drafts/issues/8979#issuecomment-1687501139)

The current spec of anchor-center tries to fit the element within the inset-modified containing block without triggering position fallback.

This doesn't work if the anchor is initially outside the containing block and can be scrolled back. In this case, the inset-modified containing block (regardless of how you computed it, via the current spec text, or current resolution of #9124, or @fantasai's alternative proposal there) is collapsed, and the element ends up not center-aligned with the anchor, but instead:

My proposal

If there's anchor-center alignment on an axis, then:

  1. Always center-align the element with the anchor without considering insets
  2. If the result of 1 overflows the scroll-adjusted IMCB and there are fallback positions, trigger position fallback
    • The scroll-adjusted IMCB should be computed following the current resolution of #9124, namely, treating any auto as 0

Discussions

I think the highest priorities are:

  1. Scrolling doesn't trigger relayout, except when fallback position is changed
  2. We should get the same layout for (i) anchors initially in the CB, and (ii) anchors that can be scrolled into CB

And I don't see any way to achieve these two at the same time if we also want to support "fitting the element within the IMCB by shifting it around", which the current spec wants to support.

This proposal also requires the current resolution of #9124. The rationale is straightforward: suppose we are positioning a popover (with position: fixed), and want it to be center-aligned with an anchor, and trigger position fallback when reaching the viewport boundaries. Then the IMCB is simply the viewport, which is inset: 0.

bfgeek commented 1 year ago

Does this depend on how the insets are resolved? E.g. If the anchor is outside the containing-block, we can resolve the insets to be the larger rect, i.e "Option I".

Inside:
+--------------------------+
|                          |
|         <--------------->|
|                          |
|               +---+      |
|               |   |      |
|               | A |      |
|               |   |      |
|               +---+      |
|                          |
+--------------------------+

Outside I:
+--------------------------+
|                          |
|<-------------------------+----------------------------->
|                          |
|                          |   +---+
|                          |   |   |
|                          |   | A |
|                          |   |   |
|                          |   +---+
|                          |
+--------------------------+

Outside II:
+--------------------------+
|                          |
|                          |   <--->
|                          |
|                          |   +---+
|                          |   |   |
|                          |   | A |
|                          |   |   |
|                          |   +---+
|                          |
+--------------------------+

The nice thing about the current approach - is that shrink-to-fit sizing "just works" e.g. it'll expand up to the current area which is desirable.

(There are a few other variations, e.g. Option II if outside will expand up to the size of the anchor, another variant would be to expand up to the edge of the original containing block).

xiaochengh commented 1 year ago

How exactly do Outside I and Outside II work?

Are we going to use different IMCB algorithms when anchor is initially inside vs. outside the containing block, and vs. those partially in CB? And if so, if the element can be scrolled back into CB, does the IMCB algorithm change based on the scroll offset?

If the answer is yes, then it causes relayout on scrolling. If no, then we'll have different layout results for anchors initially in CB and anchors that can be scrolled back into CB. Neither seems desirable.

(I should also add this point into the "discussions" section)

tabatkins commented 1 year ago

How exactly do Outside I and Outside II work?

I assume Outside 1 is "distance between center of anchor and further side of the containing block, then the same distance to the other side". Dunno what the Outside II is, tho I don't think Ian is proposing anything about it.

Are we going to use different IMCB algorithms when anchor is initially inside vs. outside the containing block, and vs. those partially in CB? And if so, if the element can be scrolled back into CB, does the IMCB algorithm change based on the scroll offset?

It sounds like that's what Ian is suggesting, yes. That does mean a (relatively minor) jump as the anchor falls completely outside of the CB - the abspos stops sliding to stay in the CB and instead jumps back to following the anchor.

But hm, I think I'd prefer to just extend the "sliding" behavior if possible, to let it slide out of the CB when the anchor goes out:

  1. If possible, center the abspos over the anchor, except:
  2. If centering would cause the abspos to overflow its IMCB, instead slide it off-center to keep it in the IMCB, except:
  3. If the anchor is smaller than the abspos, then as the anchor's far edge leaves the IMCB, align the abspos's same edge with it. (As it starts to leave, it pulls the abspos with it.)
  4. If the anchor is larger than the abspos, then as the anchor's near edge leaves the IMCB, align the abspos's same edge with it. (As it finishes leaving, it pulls the abspos with it.)

This avoids jumps - each of the three modes smoothly picks up where the previous left off. This also keeps the abspos and anchor near each other even when the anchor is way off-screen, so you don't have the abspos accidentally hanging around on-screen.

(That said, this sort of "be sticky to the anchor" behavior might be useful more generally; off-line discussion with @xiaochengh suggests that it is. I'll chat with them more about that and see if it's reasonable to make the sliding/sticking a more general feature that'll apply to more cases than just anchor-center, in which case we can simplify anchor-center to just be "always center", no built-in overflow avoidance.)

kizu commented 1 year ago

The “sticky to the anchor” behavior sounds very promising, can't wait to see what you will decide about it!

tabatkins commented 6 months ago

Retagging to level 2, since we moved the other "sliding" stuff to level 2.