w3c / csswg-drafts

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

[css-anchor-1] Introduce CSS Anchor Positioning #7282

Closed bfgeek closed 2 years ago

bfgeek commented 2 years ago

This is a placeholder issue to introduce CSS Anchor Positioning to the CSSWG.

Explainer: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/CSSAnchoredPositioning/explainer.md See - https://tabatkins.github.io/specs/css-anchor-position/ for a rough overview of the current thinking.

css-meeting-bot commented 2 years ago

The CSS Working Group just discussed Anchor Positioning.

The full IRC log of that discussion <TabAtkins> Topic: Anchor Positioning
<TabAtkins> github: https://github.com/w3c/csswg-drafts/issues/7282
<fantasai> ScribeNick: fantasai
<fantasai> iank_: Quite a lot of interest in positioning an element relative to another element in the DOM
<fantasai> iank_: what we're proposing here isn't a new idea, ppl have had variants of this idea for over 10 years
<astearns> explainer: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/CSSAnchoredPositioning/explainer.md
<fantasai> iank_: comments on Tab's blog in 2012, etc.
<fantasai> iank_: This is basically an extension to absolute and fixed positioning
<TabAtkins> s/comments/a post/
<fantasai> iank_: in that we can set the inset properties, left/right/top/bottom
<fantasai> iank_: and interpret that relative to another element
<fantasai> iank_: We've got a prototype of this, and found it to be pretty powerful
<fantasai> iank_: you can create popups with this, all sorts of things
<TabAtkins> (the old post: https://www.xanthir.com/blog/b48H0)
<fantasai> iank_: Tab's written up a basic spec for this, with details of how application works, how this modifies the abspos/fixedpos scheme
<fantasai> iank_: and how also the rectangles propagate
<fantasai> iank_: couple of interesting point in that one thing we thing is ?? is that when you propagate up the positions of the anchor elements
<fantasai> iank_: we think it's should roughly follow the same propagation as static elements, in that it ignores transforms and ???
<fantasai> iank_: So that you can still have composited text and not affect layout (?)
<fantasai> iank_: I think that's roughly it
<fantasai> TabAtkins: There's a limitation on which elements can be targetted with anchor
<fantasai> iank_: Roughly speaking, abspos/fixedpos happens right at the end of laying out a container, so you already know where all your in-flow children are
<fantasai> iank_: you get some really nice properties if you restrict it to elements within that containing block subtree
<fantasai> iank_: [missed]
<fantasai> iank_: When we get to abspos/fixedpos positioning, you can reference things that we already know where they are
<Rossen_> q+
<TabAtkins> ScribeNick: TabAtkins
<TabAtkins> iank_: The other thing is @position-set
<TabAtkins> iank_: When you examine the popup/anchor use-cases, necessary ot be able to say "I don't fit in this position, I'd like to try an alternate position"
<TabAtkins> iank_: So you might want to be on the right of the anchor, but if there isn't space I"d like to be below, or the left. That's what @position-set is for
<TabAtkins> iank_: @position-set lets you specify @try blocks setting top/left etc, and if those don't work (cause overflow) we advance to the next @try and use those instead.
<smfr> q+
<fantasai> Scribenick: fantasai
<fantasai> TabAtkins: [missed]
<TabAtkins> TabAtkins: Possibility of exponential epxlosion in layous when you have chained anchors means we want to impose a strict limit on how many @try blocks can be used
<fantasai> Rossen_: Generally I'm favorabl to the scenario and the overall approach
<fantasai> Rossen_: couple of questions not clear to me, if I heard you right, you said that you can anchor yourself to any other element's box
<fantasai> iank_: in the containing block subtree that's already being positioned
<fantasai> iank_: abspos/fixedpos has its containing block
<fantasai> iank_: anything that has already been positioned within that containing block subtree
<astearns> which is an *ancestor* in the containing block subtree
<TabAtkins> See https://tabatkins.github.io/specs/css-anchor-position/#target-anchor-element for details
<fantasai> iank_: so you can't reference something further up the DOM
<fantasai> Rossen_: This was exactly my question here
<fantasai> Rossen_: and think it's really important in order to prevent some of the really circular dependencies
<fantasai> Rossen_: question is still, is the assumption that such element will not contribute to the overall bounds of the containing block
<fantasai> iank_: right, this will only apply to abspos/fixedpos elements
<fantasai> iank_: so they won't change the containing block size
<fantasai> (but presumably would change scrollable overflow area)
<fantasai> Rossen_: This feature you describe is almost exactly the feature we proposed called "position: float" or something like that
<fantasai> Rossen_: except that you're anchoring to elements, not allowing the rest of the positioning constructs to apply
<fantasai> Rossen_: My question was answered, you're basically scoping the anchoring to the containing block, which makes a lot of sense
<fantasai> Rossen_: only other question is, you can affect scroll bounds for your containing block still, even for those elements?
<fantasai> iank_: yes
<fantasai> Rossen_: so behave like normal abspos
<fantasai> iank_: yes
<fantasai> iank_: You're right that you need to make the scrollbars predictable, but this isn't a new problem
<fantasai> Rossen_: not different than if just an abspos
<fantasai> Rossen_: last bit, are you scoping only to anchoring, or anchoring plus... can I say anchor me next to the left border + some offset?
<fantasai> iank_: These anchor queries you can use in a calculation expression
<fantasai> iank_: so you can do calc(this + this)
<fantasai> iank_: we had some fun with our happy prototype, where you could do minimum of this anchor's left and this other anchor's left
<astearns> ack smfr
<fantasai> smfr: Is there potential for circular references?
<Rossen_> q-
<fantasai> iank_: We want to avoid exactly that
<fantasai> iank_: so anchor-positioned things assigned to the same containing block can't reference each other
<iank_> https://tabatkins.github.io/specs/css-anchor-position/#target-anchor-element
<fantasai> iank_: Tab's got all the rules written down in the spec
<fantasai> TabAtkins: very certain not a problem
<dholbert> q+
<chrishtr> Anchoring can only apply *down* the containing block chain, which makes it clear that there are no cycles.
<fantasai> smfr: because constrained to something in the containing block, if authors want a global ability they'd have to anchor ...?
<fantasai> iank_: have to use fixedpos or something like that
<fantasai> TabAtkins: No need to reparent, because fixedpos containing block is the ICB
<fantasai> smfr: ...
<fantasai> iank_: But then there's things where you want it to work more locally
<fantasai> iank_: There's also a proposal which is related to adjusting the scroll position
<fantasai> iank_: but that's separate from this
<astearns> ack dholbert
<fantasai> dholbert: I was wondering, seems like it's ID-based right now, I wonder if that could be ... how do you imagine using this if you want to have multiple in a single page?
<fantasai> TabAtkins: where are you seeing this?
<fantasai> dholbert: looking at explainer
<fantasai> TabAtkins: Ah, MS explainer is earlier draft
<fantasai> TabAtkins: look at this spec
<fantasai> TabAtkins: we use the anchor-name property, look for the first thing in tree space with that name
<astearns> ah, I only read the explainer - not the spec yet :)
<fantasai> dholbert: okay
<fantasai> iank_: We've got some flexibility in how we do that
<fantasai> iank_: I personally like anchor-name solution
<fantasai> iank_: requirement is reference things within this containing block subtree
<astearns> ack fantasai
<TabAtkins> fantasai: Whatever scoping rules we use here we should be consistent with scroll animations, which has a similar named attachment method
<fantasai> (and vice versa, they're both early proposals so we switch to whatevers' the best method for both)
<fantasai> astearns: Suggest to adopt the spec and fiddle with details in the spec
<fantasai> iank_: if anyone wants to play with the prototype lmk
<fantasai> TabAtkins: We anticipate asking for ED soon-ish, not just yet
<fantasai> TabAtkins: so keep informed
<fantasai> s/adopt/read/
<fantasai> astearns: I assume there'll be some discussion in your personal repo for awhile, but if significant changes or questions raised, migth be good to update the issue we have on introducing this
<fantasai> astearns: so ppl can follow along without following your repo
<fantasai> TabAtkins: happy to track issues in both repos
<fantasai> TabAtkins: and move issues later
<fantasai> fantasai: Why not move it now?
<fantasai> TabAtkins: no particular reason
<TabAtkins> The scoping rules for anchor-name are just "the subtree that is allowed to contribute an anchor due to the positioning rules", which may or may not match up with what scroll animations exactly want
<TabAtkins> ScribeNick: TabAtkins
<fantasai> faceless: better to move now then, your private repo isn't backed up by W3C
<fantasai> s/faceless/fantasai/
FremyCompany commented 2 years ago

Honestly, I feel like the current API is too complex. The "basic" use case requires dozens of lines of code, I'm not sure this makes sense.

You have to do lots of math to do basic behaviors like anchoring always to the bottom right of the anchor without fallback.

FremyCompany commented 2 years ago

I am not sure also how this API handles multiple popups that should not overlap each other. But maybe that should be a separate issue?

For instance, the demo with the bar chart, if two bars have the same height, wouldn't the labels draw on top of each other?

css-meeting-bot commented 2 years ago

The CSS Working Group just discussed CSS Anchor Positioning, and agreed to the following:

The full IRC log of that discussion <fantasai> Topic: CSS Anchor Positioning
<fantasai> github: https://github.com/w3c/csswg-drafts/issues/7282
<fantasai> TabAtkins: presented early idea in May
<fantasai> TabAtkins: continued working on it
<fantasai> TabAtkins: Jay has prepared a slide deck intro with details
<TabAtkins> s/Jay/Jhey/
<xfq> https://jhey-presents.netlify.app/tpac-2022/
<fantasai> jhey: CSS needs you! So want input on shaping where this goes
<fantasai> jhey: anchoring on the Web is a common pattern, very tricky, and headache for developers
<fantasai> ... when do I do it, how do I do it?
<fantasai> ... How to calculate the position, can I do it in an attriute
<fantasai> ... it's used for tooltips, menus, things driven by interaction
<fantasai> ... but the most common pattern is pop-ups, things that need to get into the top layer
<fantasai> jhey: Thinking of a tooltip, we have a containing viewport, and then we have the anchor thing like a tooltip, and then the anchor which is a button or something
<fantasai> ... and then have the arrow visually connecting the two
<fantasai> jhey: There are workarounds using abspos, requiring a special DOM structure involving wrappers and relpos
<fantasai> ... potential invalid HTML to put things inside other things
<fantasai> ... it'shard to scale or respond to viewport changes
<fantasai> ... might go with an example like this (shows code example)
<fantasai> ... you could go different route without a wrapper, then need to work out positoins
<fantasai> ... but it's hard to maintain
<fantasai> jhey: could use JS, but then need boilerplate, and styles are leaking into scriptland
<fantasai> ... then what info do you need, how to calculate offsets, etc.
<fantasai> ... (shows code example)
<fantasai> jhey: All of those solutions look the same
<fantasai> ... user sees it looks greatn, but dev experience is not great
<fantasai> ... done right this could be much better for a11y etc also
<fantasai> jhey: There's issues!
<fantasai> ... when something goes out of the viewport, if things change, how do we change? what about scrolling?
<fantasai> ... Lots of edge cases
<fantasai> jhey: Someone solved it?
<fantasai> ... there was one called tether.js, another popper.js
<fantasai> ... interactions are handled by JS, very config-heavy
<fantasai> ... lots of things to decide on, and another dependency to maintain
<emilio> q+
<fantasai> ... it gets the job done, but devs don't typically like adding extra JS files
<fantasai> jhey: Another is Floating UI, less download, but is it better to use, still extra dependency, which to use?
<fantasai> jhey: How about we keep the styles in the styles and use a new anchoring API?
<fantasai> ... we have container, viewport, tooltip
<fantasai> ... think about viewport like ocean, anchor is anchor , and chained to the tooltip
<fantasai> ... here the browser is working out hwere to put it. Not enough room for the boat here? shift it down
<fantasai> ... no depedencies no wrappers
<fantasai> jhey: We're experimenting and learning, I've got some demos here
<fantasai> jhey: Basic anchor, this is how it looks
<fantasai> ... no DOM structure required, can live anywhere
<fantasai> ... here I've got two boats tethered to the same anchro
<fantasai> ... I have an anchor name, tether to it
<fantasai> ... passing anchor name and use whichever position I want
<fantasai> ... I'm using clacl here, can use inside calc
<fantasai> ... and then anchor-side will get the width/height of anchor
<fantasai> ... browser will work out the offsets as I move things around
<fantasai> [What's happening slide]
<fantasai> jhey: Containment works as ussual, browser handles offsets for us
<fantasai> ... different fallback positions
<fantasai> ... if boat can't fit in the ocian here, then move it somewhere else
<fantasai> ... UA does it for me
<fantasai> ... use position-fallback to attach to fallback list of positions
<fantasai> .. can change containment, is contained by viewport or something lower in the tree
<fantasai> ... can clip x axis or y axis
<fantasai> ... or both
<fantasai> ... same demo again where constrained by scroller instead of allowed to leak
<fantasai> jhey: Things needed are things liek popups
<fantasai> ... being able to anchor things in the top layer
<fantasai> ... you can do this currently with JS solutions, but they do hit some limits
<fantasai> ... wrt resizing
<fantasai> ... Another is <selectmenu>
<fantasai> jhey: Where this gets really cool, you can do some interesting things
<fantasai> ... we have a chart, can use anchor positions in calc() I can tether a tooltip to the chart
<heycam> q+
<fantasai> ... and attach the min and maximum, and it'll work it out for me
<fantasai> ... you can use more than one anchor in your positioning
<fantasai> ... or anchor to highest bar or lowest bar
<fantasai> ... can also do nested menus, holy grail of anchoring
<fantasai> ... just anchor to something inside, and works well, menus squishes as viewport gets narrower
<fantasai> jhey: A few open questions
<fantasai> ... how to detect which side to put your arrow?
<fantasai> ... how do we scope things like position-fallback
<fremy> q+
<astearns> ack emilio
<fantasai> emilio: I had a question, seen a lot of ways of when viewport resizes, most of the fallback is clipping or shrinking
<fantasai> emilio: how easily can you do sliding fallback instead?
<fantasai> emilio: when container goes out of view
<emeyer> q+
<fantasai> emilio: thinking about how some native platforms and even Gecko's popups specify after position, and the way we do it, you have an anchor node and you specify the side of the anchor and the side of the popup you want to align
<fantasai> emilio: e.g. top left top left, woud put your item on the bottom by default
<fantasai> emilio: would give you various ways to figure out the final position if you don't fit
<fantasai> emilio: it not be so powerful with offsets, like the fancy chart anchoring was pretty cool and not sure to what extent could do
<fantasai> ... but for anchoring to single thing, seems much easier to reason about vs doing all the math and fallbacks yourself
<fantasai> ... Have you thought about that kind of API< you can specify where the popup goes relative to anchor?
<fantasai> ... we allow customization with margins
<fantasai> ... so we use the top/left margin to shift in the direction you're anchored
<fantasai> ... so was wondering what kind of exploration you've done of this kind of space and other ways in platform
<fantasai> ... what Gecko does is very similar to what ??? does
<fremy> q- because I had the same remarks as emilio
<fremy> q-
<fantasai> ... I don't think Windows has a native thing
<fantasai> iank_: We did do a more limited version of this, anchor to a single version
<fantasai> ... similar to what you're describing
<fantasai> ... we found though that yes, it covers the 60-70% case, but you start to lose out on some of the slightly more advanced cases
<fantasai> ... and there are cases, multiple anchoring thing, is quite useful for a number of use cases
<fantasai> iank: [missed example]
<fantasai> TabAtkins: You might wanto use min/max zero or 100%
<fantasai> ... or fallback 0 or 100%
<fantasai> ... so you're anchored to the side until anchor goes off the screen
<fantasai> ... Right now here with the pop up tersm, it's pretty awkward right now
<fantasai> ... Maybe these cases are simple enough to use syntax like you suggested
<fantasai> ... but this should be a reasonable case, and not require hundreds of @position-fallback rules, because that's bad
<fantasai> [shows content out demo]
<fantasai> emilio: In your example where the container shrinks, the positioned elements flips from below to on top of anchor
<fantasai> ... but in one example gets clipped instead of remaining in viewport
<fantasai> ... inside a container instead of viewport
<fantasai> ... if you keep shrinking, it could be kept inside, but then leaks
<fantasai> ... by default, authors won't test all combignations, and things will be offscreen in some cases
<astearns> zakim, close queue
<fantasai> ... so more declarative could allow UA could make sure that the positioning is on-screen
<Zakim> ok, astearns, the speaker queue is closed
<astearns> q?
<fantasai> iank_: any time that we tried to go, "ok, we want this behavior", there's a use case for opposite vehavior
<fantasai> ... some cases do actually want it fixed
<fantasai> iank_: hear your concern, but there's a plethora of use cases and all of them want something slightly different
<fantasai> ... similar argument could be made for testing all possible screen sizes, and yeah you need to test
<astearns> ack heycam
<fantasai> heycam: Thanks for presentation, a few questions
<fantasai> heycam: the pop-up thing, does that always move to the top layer or not required?
<fantasai> TabAtkins: not required
<fantasai> TabAtkins: if using popup API, moves to top layer
<fantasai> ... but otherwise treated as abspos
<fantasai> iank_: The containing block, you can only reference anchors within that contianing block
<fantasai> ... so useful for components
<fantasai> ... so go to the scrolling example, here the contianing block is inside the scroller so it stays inside
<fantasai> heycam: One question is what happens when there are transforms between anchored thing and anchored
<fantasai> iank_: Similar rules, scrolling is complicated and want to talk about that separately
<fantasai> ... but for transforms use staticpos propagation rules, basically assume no transforms
<fantasai> heycam: no transforms?
<fantasai> emilio: transforms make a containing block for fixed descendants
<fantasai> iank_: thing that breaks is if you're transforming the anchor, that does break
<fantasai> ... there's a tradeoff here in that this is fundamentally a layout effect
<fantasai> ... so animating a transform, don't want to slow it down
<fantasai> ... there is an option to incorporate transform
<fantasai> heycam: what about shadow tree and visibility of names?
<fantasai> ... is this another example of issues around exposing names to shadow trees?
<fantasai> TabAtkins: yes
<fantasai> ... using anchor name itself isn't problematic, because it's a tree search
<fantasai> ... but for the fallback rule and its name, that has the same problems we have in other rules like @keyframes
<astearns> ack emeyer
<fantasai> emeyer: seems like a lot of the xamples use a lot of calc'ing,
<florian> +1 to emeyer
<fantasai> ... I wonder if anchor-side keywords in the draft, are those supposed to be ands, can they be ors?
<fantasai> ... so you could say somehting liek center left?
<fantasai> iank_: A lot of these use left/right, and haven't implemented center
<fantasai> ... so many oculd be replaced with left center
<fantasai> emeyer: So popup in the middle, wouldn't need calc?
<fantasai> jhey: could use percentages
<Bert> (For the historians: Around 1997, Håkon and I discussed floats with anchors and ‘elastic bands’, to try and keep floats near their anchors or near each other, depending on the strength of the ‘elastic’. Among the goals were sidenotes and parallel texts, such as a text and its translation. The difficulty for the author to know whether to write "see on the left" or "see on the right" was one reason we decided to postpone that feature.)
<fantasai> emeyer: so for simple things might not need calc()
<fantasai> emeyer: My other question is, am I understanding that a popup can be placed in relation to multiple anchors?
<fantasai> TabAtkins: yes
<fantasai> emeyer: so text with footnote reference in the middle, could have the footnote could be vertically center-aligned but have its edge against the column of text
<fantasai> TabAtkins: yes
<fantasai> emeyer: ok!
<fantasai> jhey: [missed]
<fantasai> astearns: So little over time
<iank_> q?
<fantasai> TabAtkins: I'd like to request resolution
<fantasai> ... last time was to have a UD, haven't done that yet
<fantasai> ... but it seems like to become an ED at this point
<fantasai> ... so would like to request an ED of this draft
<fantasai> astearns: Any objections?
<fantasai> [none]
<fantasai> [discussion of editors]
<fantasai> RESOLVED: ED of Anchor Positioning, editor TabAtkins iank_ jhey
<fantasai> astearns: Please make ED asap so we can file issueS!
<fantasai> iank_: I'm free to chat during break
tabatkins commented 2 years ago

@FremyCompany please raise new issues for questions; I've added a label for the spec now.

You have to do lots of math to do basic behaviors like anchoring always to the bottom right of the anchor without fallback.

?? It's top: anchor(--foo bottom); left: anchor(--foo right);. Fallback requires more work, but the basic behavior is as simple as it can possibly be.

I am not sure also how this API handles multiple popups that should not overlap each other. But maybe that should be a separate issue?

Yes, separate issue.

FremyCompany commented 2 years ago

For the first issue, I was thinking of cases where you want some breathing room between the popup and the position. You cannot use margin, because if the popup ends up moved, the margin will apply in the wrong direction. So you have to use calc() to apply the margins.

But yes, I will open new issues ;-)