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] Grid-based anchoring syntax? #9145

Closed
tabatkins opened this issue Aug 2, 2023 · 6 comments
Closed

[css-anchor-position-1] Grid-based anchoring syntax? #9145

tabatkins opened this issue Aug 2, 2023 · 6 comments

Comments

@tabatkins
Copy link
Member

tabatkins commented Aug 2, 2023

One of the major syntax distinctions between the current spec and the grid-based proposal was the grid-based syntax itself. At its core, it gave a way to specify a containing block for the positioned element in terms of a 3x3 grid, with lines set up relative to the containing block's edges and the anchor's edges.

Some of my teammates remarked that they did find expressing simple positions via the grid to be more intuitive; particularly, having to write things like left: anchor(right); can be a little difficult to parse if you're not already thinking in terms of the inset-modified containing block. (Which direction keyword is the positioned element vs the anchor, etc.)

If this mental model is worth accommodating, we can bake that into the current proposal pretty easily, via an alternative 'inset' shorthand:

Name: inset-area
Values: <the [grid syntax from the grid proposal](https://fantasai.inkedblade.net/style/specs/css-anchor-exploration/#anchor-area%E2%91%A0)>

For example, the slides had one case that used position-area: top / start center; to position the element into row 1, column 1-2 - above the anchor element, aligned between the left edge of the containing block and the right edge of the anchor.

In the current spec you'd write that as bottom: anchor(top); right: anchor(right);; in this proposal you'd alternately be able to write inset-area: top / start center; and get the same effect.

Some open questions:

  • In the example above, should top and left be auto or 0? Probably makes sense to have them be auto if we go with [css-align-3][css-position-3] Better interaction of auto insets and self-alignment properties? #9124's idea; that way the default will push the positioned element flush with the anchor, which is probably what's intended, but allow the author to still get full alignment control if that's what they need.
  • Should this just be an alternate syntax branch of inset itself, rather than a separate shorthand? I think it's completely grammatically distinct, but it probably removes any possibility that we could reserialize with the grid form. (That is, if you asked for the computed style of 'inset' in the above example, it would have to return auto anchor(right) anchor(bottom) auto, rather than top / start center.)
  • What happens when the anchor element is partially or completely overflowing the abspos's containing block? I don't think this is answered in the Grid proposal. If we just ignore that and handle it naively I think we still get a good answer - it'll be aligned in the same way regardless, you just might have zero space in your inset-modified containing block for alignment values to work on.
@Loirooriol
Copy link
Contributor

#9125 seems unrelated, so I guess you wanted to link to something else.

@tabatkins
Copy link
Member Author

Indeed, I meant #9124

@fantasai
Copy link
Collaborator

fantasai commented Aug 22, 2023

What happens when the anchor element is partially or completely overflowing the abspos's containing block? I don't think this is answered in the Grid proposal.

It falls back to the next option. Currently, if there isn't a next option, it stays there and overflows its inset-modified containing block. There was some ideas in one of your slide decks about being able to choose other strategies for deciding among the options, though--this is something worth exploring imho, but somewhat separate question.

@fantasai
Copy link
Collaborator

fantasai commented Aug 22, 2023

In the current spec you'd write that as bottom: anchor(top); right: anchor(right);; in this proposal you'd alternately be able to write inset-area: top / start center; and get the same effect.

Well, not quite the same, because of the physical/logical differences. In RTL context, it'd be left: anchor(left). One of the interesting things that the grid-based syntax opens up, because it's keyword-based, is being able to use logical+physical combos.

Another interesting thing that it opens up is the ability to use the writing-mode of the containing block or even the anchor, not only the writing-mode of the abspos itself. We didn't really explore this, but the alignment properties do this with the e.g. start vs self-start keywords.

But the main goal was, really, to make it easier to express the author's intention in a more convenient and natural way, without requiring a lot of math-y thinking (at least for the common cases)...

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-anchor-position-1] Grid-based anchoring syntax?, and agreed to the following:

  • RESOLVED: add a separate property (can bikeshed name in future), not merely a shorthand, but interacts with inset properties in current draft
  • RESOLVED: inset-area causes 'auto' keywords of inset to resolve to appropriate anchor() functions (TBD at computed or used value time)
The full IRC log of that discussion <TabAtkins> s/Romain/Roman/
<dbaron> TabAtkins: one of the interesting parts of alternative proposal was grid-based syntax for positioning thingns. Some folks on our team found that more understandable at least in simple cases. I don't have a problem with this, easy to map in to existing model. Uses one of four easily-addressible lines you can get with inset and anchor properties.
<dbaron> ... so proposal here is to add a new 'inset-area' property that's a pure shorthand property, taking the grid syntax from the proposal (without the extra falllback bit), and expands into the four insets that would correspond to.
<dbaron> ... so saying 'top center' would expand to (missed)
<florian> q+
<dbaron> TabAtkins: a few other options we couuld go for. Could merge it into the inset syntax itself. Should be gramatically distinct from 1-4 anchor values. Wouldn't be able to serialize it back out in that case which might be annoying.
<dbaron> TabAtkins: maybe less of a problem than a shorthand-only property though.
<dholbert> q+
<astearns> ack florian
<dbaron> florian: in termrs of translating to inset properties this seems to work. One thing I'm not sure about: in the grid-based proposal there were align-content/justify-content keywords resolving differently depending on which grid area you slot into. Does that still work?
<dbaron> TabAtkins: that still works fine. The default one is you want to be flush to the anchor if you're in one of the outer cells. You get that behavior by default... because top was auto and bottom was 0 you get positioned flush with the anchor. The same applies all the way around.
<dbaron> TabAtkins: I don't believe we end up needing any special alignment behavior... I think everything we need pops out.
<dbaron> TabAtkins: but if necessary we could add more magic to alignment properties.
<astearns> ack fantasai
<dbaron> fantasai: I'm ok with trying to do this. I don't think it gets all the usability advantages of the other proposal. Just making it a shorthand doesn't give you the ability to list fallbacks; you just get one position out of it. That was an easy way to do fallback behavior in the other proposal.
<dbaron> fantasai: Another issue is that align-self and justify-self have both a start and a self-start keyword. Writing mode of self versus containing block. Usually want the containing block. When resolving shorthands during the casade, we don't know what the containing block is. Cascade mapping always done using writing mode of element itself. So don't have ability to position based on container's writing mode (or, in theory, even anchor's
<dbaron> writing mode). Could do that in a keyword-based syntax.
<dbaron> ... In a keyword based syntax resolve the value at computed value time. But when resolving the directional properties, in the cascade, we don't have the full style information so the only writing mode we can reference is the element itself.
<dbaron> fantasai: That's one thing that doesnt' work with shorthanding.
<emilio> q+
<dbaron> fantasai: Thirrd thing this doesn't address is the abilitity to conditionally style absolutely positioned element or its contents.
<dbaron> fantasai: Because there's a concept of which slot you're in that's a higher level concept than which coordinates you end up, that allows conditional styling using either pseudo-classes or @container rules.
<dbaron> fantasai: That allows styling depending on where it ends up. Even if you specify a logical position you can select based on a physical position.
<dbaron> fantasai: Can style based on left/right/bottom/top even if it was specified as 'start start'.
<dbaron> fantasai: That was an advantage of having something conceptual in the other proposal rather than being syntactic sugar.
<dbaron> fantasai: That allows some of the extra power in that proposal.
<dholbert> q-
<dbaron> TabAtkins: first and third points about fallback and conditional styling would be downstream issues . I want do solve those as well...
<jensimmons> q+
<dbaron> TabAtkins: for number 2, being able to expand based on container rather than self writing mode -- that's a good point and a little problematic.
<dbaron> TabAtkins: I wonder if we want to solve that instead by having inset-area not be ashorthand, but instead be preserved, and have it provide different anchor values when the anchors are auto.
<xiaochengh> q+
<dbaron> TabAtkins: This can be late enough that we'd have appropriate writing mode information.
<florian> +1
<dbaron> TabAtkins: the author experience should be essentially identical
<dbaron> astearns: would that also solve the fallback thing?
<iank_> likely should be fine to resolve insets based on an additional property during layout time.
<dbaron> TabAtkins: it could, but I want to address fallback separately as a different issue. I want to make sure we have a fallback story for anything. Open to idea of inset-area doing fallback, but want to make sure we're not inconsistent with rest of fallback.
<dbaron> fantasai: I didn't quite understand what TabAtkins is proposing.
<dbaron> TabAtkins: inset-area no longer a shorthand, just a separate property (same grammar). Effect would be that if insets are auto, it provides insets. So by default you'll be put in the right grid cell. In theory you could override them. If you want to put something roughly in this grid area and then tweak, I think it's useful to say 'right' is this expression.
<dbaron> fantasai: Brings up another issue with other proposal... select agrid area, and insets would inset in *from that*. Allowed for a lot less math for common/intermediate cases.
<dbaron> fantasai: ... this allowed making percentages relative to the outer track, which gave some abilitiies that are possible to do in your proposal but messier to express.
<dbaron> fantasai: ... lets you do many things with less fussing with math expressions.
<dbaron> fantasai: ... Not saying we shouldn't do this... seems like it's an improvement over what's there. Happy to accept the changes, but not sure it's solving the whole question.
<dbaron> TabAtkins: Can tweak the position with margin rather than insets.
<dbaron> TabAtkins: or if you want to rejigger can use calc() of a margin minus a value.
<iank_> some of the cases for using insets in the Alt. Proposal aren't needed, e.g. can do `left: anchor(center);` , vs. `left: 50%`
<florian> q?
<florian> q+
<dbaron> jensimmons: I wonder if it would help if you looked at the code ... I think there is something about having a margin and having an inset, and having inset insetting from the area that's been chosen. E.g., a margin of 1em and an inset of 50%. So it fills 50% of the column *and* has a 1em margin so it never touches the edge of the viewport. Could use more thinking about how to maintain advantages of other proposal.
<dbaron> TabAtkins: I think that case is easy to express in either proposal.
<dbaron> TabAtkins: doc... hasn't explored (missed)
<dbaron> astearns: we have a queue... I don't think we're going to get to (missed) in the breakout today.
<astearns> ack emilio
<dbaron> emilio: I was going to argue against the shorthand, because it needs to be parse time rather than cascade time... but that point is moot now. I think making it a longhand an affect auto inset resolution seems fine.
<dbaron> emilio: I think a bunch of inset cases that jen and tab were talking about can be margin: calc(50% + 1em)
<dbaron> fantasai: they can't
<astearns> ack jensimmons
<dbaron> jensimmons: TabAtkins, can you say more about why inset-area is a good name?
<dbaron> TabAtkins: no strong opinion on the name, first name that came to mind.
<iank_> i don't think we should shorthand `position`
<dbaron> jensimmons: we used position-area. Two thoughts about that: would be a longhand (?) within position. What surprises me about inset-area as a name is that it ties back to points fantasai was making:
<dbaron> jensimmons: ties to a different mental model: I'm g oing to put thing in these cells, and then apply an inset on top of that. WHereas inset-area is saying "here's my inset", so you don't get inset on top of that. So different interpretation for web developers.
<dbaron> jensimmons: so not sure inset-area is the right name
<dbaron> TabAtkins: I wanted to keep it under inset since it affects inset properties, but not strongly attached.
<dbaron> fantasai: I think for the definition you're giving it, inset-* makes sense, but for the definition we gave I think a non inset-* name makes sense.
<astearns> ack xiaochengh
<dbaron> xiaochengh: There's an issue if we make inset-area not just shorthand but a standalone property: interaction with animations. If it's standalone then it's not going to animate at all. With anchor functions developers have made demos with animations. If we introduce inset-area we'll end up in weird situations where you can animate with anchor functions but can't animate when inset-area is used.
<dbaron> TabAtkins: that's true
<astearns> ack fantasai
<Zakim> fantasai, you wanted to respond about animations
<dbaron> fantasai: I don't think that's true -- Tab's proposal was that auto keywords of inset would compute differently. Animations is based off the computed value. So you'd have auto compute through to the correct anchor function, so I think it would animate correctly.
<dbaron> TabAtkins: Yeah, it works if we do it at computed value time -- I think we could make that work.
<dbaron> astearns: yeah, would need to be specified how animations work with values of inset-area
<dbaron> TabAtkins: not specifically, just would need to be specified that it happens at computed value time so animation behavior falls out
<dbaron> emilio: not sure how the auto behavior works at computed value time
<dbaron> fantasai: not computed to a fixed offset, but compute to an anchor function that's specified as something that you can calc()
<dbaron> TabAtkins: yeah, every auto anchor will either remain auto, become 0 or 100%, or become anchor(left/right/top/bottom).
<dbaron> TabAtkins: those are values that are interpolable via animations
<dbaron> emilio: And the anchor() function can be interpolated via calc()?
<dbaron> TabAtkins: returns a length
<dbaron> emilio: seems sketchy to make computed values of the properties depend on each other.
<dbaron> emilio: needs to be spec'd really carefully
<dbaron> emilio: right now inset:auto always computes to auto always. Introducing property dependencies is tricky but not super tricky.
<dbaron> flackr: I think computed value interpolation would be helpful for other auto animation cases as well. +1 to pursuing it.
<dbaron> emilio: Isn't a more general fix making auto interpolable and in calc().
<dbaron> fantasai: Wouldn't solve this problem because we're trying to make the inset-area values interpolable. They're keywords that put you into positions in gridded model of relationships to anchor. They're keywords and don't compute through to anything. By making them influence the inset property's auto keyword that's what makes them interpolate.
<dbaron> fantasai: So if you're partway through a transition between 2 keyword values of inset-area, your left value is not auto and therefore doesn't reference inset: auto when you're halfway between... it's an expression with anchor(left), etc. and progress.
<dbaron> emilio: Does this mean to animate the inset area you need to set transition: inset instead of transition: inset-area? That's weird.
<dbaron> fantasai: yeah.
<dbaron> TabAtkins: You want to immediately transition the inset-area so that you can get a transitionable change to the insets.
<dbaron> s/yeah./yeah... or both/
<dbaron> astearns: we should say we need to solve the animatability and move on
<dbaron> TabAtkins: remember the alternate proposal doesn't have animation behavior
<astearns> ack florian
<dbaron> astearns: back to thequeue
<dbaron> florian: I don't quite know what we'll land on eventually, but in spirit of iterating seems like a good idea. One thing that seems to have been dropped: in the Apple proposal this changed how percentages are resolved. I suspect we can't do that on margins. One reason to use insets rather than margins is that you can resolve percentages differently on them. That seemed useful, but not sure how to resurrect in this model.
<dbaron> florian: ... worth figuring out how.
<dbaron> TabAtkins: All the examples can be done pretty trivially with inset manipulation. I think the percentage behavior was strange -- depended on where positioned and I think on what the value (?) was.
<iank_> florian: some of the cases which require alt. percentage resolution, are easier expressed as `left: anchor(center)` in the current proposal
<dbaron> TabAtkins: Say something was positioned in top center, left: 50% was relative to width of the one of the cells... 150% was ... transitioned?
<dbaron> fantasai: no
<dbaron> TabAtkins: ah, ok, just left and right relative to different things.
<dbaron> TabAtkins: If we can avoid bespoke percentage behavior I"d appropriate.
<dbaron> appreciate it.
<dbaron> florian: I think we should log this and come back to revisit later, and see whether we caught all the things in the other model that could be done with percentages to make sure we didn't drop something.
<dbaron> iank_: Should make sure cases where you needed left: 50% versus left: anchor(center). So cases where you don't need specialized percentage resolution.
<dbaron> fantasai: Works for 50% but not for other values.
<dbaron> iank_: but I think that's the main use case
<dbaron> jensimmons: Speaking of use cases: a little earlier at the f2f we agreed we'd create a shared doc with use cases and code. I think somebody at Google started a doc but we couldn't find. But we created a new doc on Monday.
<dbaron> nsull: I shared an example doc with you.
<dbaron> jensimmons: so we should work on this doc... good idea.
<fantasai> s/Monday/Monday, with just what we had collected, so it's quite sparse/
<dbaron> nsull: I think each model was good at some things and harder to express other things.
<fantasai> s/with you/with you last night/
<dbaron> nsull: ... and other places where room for improvement. Neat to see examples written out.
<dbaron> fantasai: Just want to +1 to florian. A lot of things to work on but happy to make incremental progress. Should be clear that we're still exploring how this work,s but happy to draft exploration into the draft.
<dbaron> astearns: I think consensus on adding a separate property (can bikeshed name in future), not merely a shorthand, but interacts with inset properties in current draft. Is that a good summary?
<fantasai> I think for the definition we're discussing here, 'inset-area' is a reasonable name. Depending where we end up, might need to rename.
<florian> +1
<dbaron> RESOLVED: add a separate property (can bikeshed name in future), not merely a shorthand, but interacts with inset properties in current draft
<dbaron> astearns: any other things we should resolve on now?
<dbaron> fantasai: the current definition is that it causes the auto inset keywords to compute to anchor functions
<dbaron> proposed: the values of this new property cause the auto inset keywords to compute to anchor functions
<dbaron> emilio: I think this is very weird. I think an alternative is (missed)
<fantasai> s/(missed)/if you want animations, just use anchor() inside 'inset' properties/
<dbaron> TabAtkins: The reason we shifted away from parse time was to use writing mode information. Reason to shift to computed value time was for animation.
<dbaron> TabAtkins: do you want late but after computed value? Parse time, computed value time, or layout/used value time?
<dbaron> emilio: I'd prefer used value time
<iank_> we can try the used value time initially then see if we get author feedback
<dbaron> TabAtkins: I think they're equivalent in all cases except for animation
<dbaron> florian: Inline issue for this: either computed value time which is complicated and solves animations, or used value time and we need to find another solution for animations
<dbaron> TabAtkins: can resolve that it happens at computed value time or later
<flackr> +1
<dbaron> astearns: ok, so no resolution on this right now
<fantasai> PROPOSED: inset-auto causes 'auto' keywords of inset to resolve to appropriate anchor() functions (TBD at computed or used value time)
<florian> +1
<fantasai> And we might change that definition later, but for now, that's what we're at
<emilio> +1
<dbaron> RESOLVED: inset-area causes 'auto' keywords of inset to resolve to appropriate anchor() functions (TBD at computed or used value time)
<dbaron> fantasai: not 100% sure we want to stay here, but it's where we're going now
<dbaron> TabAtkins: yeah

@mfreed7
Copy link

mfreed7 commented Feb 26, 2024

Should be addressed by the current draft spec.

@mfreed7 mfreed7 closed this as completed Feb 26, 2024
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

5 participants