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] position-anchor should be defined as a longhand of position #10321

Open
fantasai opened this issue May 13, 2024 · 7 comments

Comments

@fantasai
Copy link
Collaborator

fantasai commented May 13, 2024

In #10004 we proposed to rename anchor-default to position-anchor and to allow position to shorthand both arguments.

The resolution was taken to rename the property, but because people were unsure about how to define a combined syntax with position-container, a combined shorthand syntax for the two was deferred.

However the question of whether position resets position-anchor was not resolved, not edited in, and not put on the agenda for follow-up as agreed by the CSSWG.

If we are to create a shorthand syntax in the future, we need the resetting relationships to be resolved and implemented now, i.e. position needs to reset position-anchor even if it can't set it to anything but the initial value.

@mfreed7
Copy link

mfreed7 commented May 13, 2024

Yep, that makes sense. We would be happy to adopt that as a resolution and ship the corresponding change in Chrome. Perhaps we can just call for an async resolution? Or we can try to get one at Wednesday’s meeting.

@nt1m
Copy link
Member

nt1m commented May 14, 2024

@fantasai I think you meant position-anchor being a longhand of position, not a shorthand.

@nt1m nt1m changed the title [css-anchor-position] position-anchor should be defined as a shorthand of position May 14, 2024
@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-anchor-position] `position-anchor` should be defined as a longhand of `position` , and agreed to the following:

  • RESOLVED: Make position a shorthand of position-anchor and a new position-type property. The shorthand resets both.
The full IRC log of that discussion <flackr> fantasai: in earlier issue we renamed anchor-default to position-anchor, motivation was to allow position to be shorthand of this and poss other stuff later. We didn't resolve on short-handing relationship. Designing a syntax that accomodates everything can be deferred but we need to decide whether position reset it now
<florian> +1
<kizu> +1
<masonf> +1
<emilio> g+
<flackr> TabAtkins: sounds good, we don't have a strong opinion either way
<emilio> q+
<flackr> astearns: do we need a resolution for both the shorthand and that it reset?
<flackr> fantasai: yes
<flackr> emilio: It feels weird that if you had an anchored thing that is abs pos, and you want to make it fixed pos you now need to fight with the reset on position-anchor. Authors may find that confusing
<flackr> fantasai: the current values of static | absolute | fixed | etc should probably be their own longhand as well so you don't have to have that fight
<iank_> Modulo any compat constraints, shorthanding properties which have existing since the beginning of time a higher risk than others.
<flackr> fantasai: i.e. we'll have a longhand for those position values
<flackr> emilio: I think people will do position: fixed or position: absolute anyways without thinking that it reset but this is fine as a proper solution
<flackr> fantasai: our proposal for the longhand is position-type
<flackr> TabAtkins: it would be nice to have the additional longhands, i don't htink this blocks anything. It's slightly awkward but I think okay that you need to reset the anchor
<flackr> emilio: but you need to define the longhands?
<flackr> TabAtkins: not necessarily. Since it's reset only the other longhands don't need to exist
<flackr> fantasai: They do need to exist
<flackr> TabAtkins: right, internal property
<flackr> emilio: I don't think this works even if it is an internal property because shorthands aren't typically included in enumerations
<flackr> astearns: there might be a web compat risk?
<flackr> emilio: def
<flackr> TabAtkins: is that a general issue we would have with any properties becoming shorthands?
<flackr> emilio: we have the issue when it becomes a shorthand it stops getting enumerated and the longhands become enumerated. We don't have the issue that the longhand is hidden so you can't access the property
<flackr> s/can't access/ isn't enumerated
<flackr> TabAtkins: then i propose position-type
<flackr> fantasai: or position-style like text-wrap-style or list-style
<kizu> +1 to `position-type`
<flackr> florian: i like type better
<flackr> astearns: me too
<flackr> astearns: at this point, can we resolve on making position a shorthand of position-anchor and position-type?
<flackr> astearns: and then worry about the enumeration issues later
<flackr> emilio: I think this is fine. The big risk is someone enumerating styles and copying them over. If we have both longhands then it's not as much of a worry
<flackr> iank_: it's more of a risk for people manipulating styles directly. When the enumeration disappears they may be relying on position always being in the enumeration
<flackr> iank_: we've seen this before, most recently white-space, where people assume the property will read back the same as the property they set
<flackr> astearns: is this something where you would like to wait on the decision until we have a compat assessment? Would you object to a resolution?
<emilio> ack emilio
<flackr> iank_: taking a resolution is fine, but we might get regressions and have to revert and take another resolution
<astearns> ack fantasai
<flackr> iank_: shorthanding properties that have been around since time immemmorial carries risk
<flackr> fantasai: can we update the way we handle this to include shorthands in enumeration for these cases to avoid the problem?
<flackr> iank_: i think this may break things even more
<flackr> astearns: this might be worth opening another issues to discover whether the pitfalls are better or worse
<flackr> emilio: if you do this you get redundant properties. We could special case some legacy ones, but this is iffy. The order is lexicographical if you have cases where a shorthand shows up between longhands
<flackr> astearns: Okay, let's have a separate issue for enumerating shorthands, for this issue the proposed resolution is we make position a shorthand of position-anchor and a new position-type. The shorthand resets both
<flackr> fantasai: and we should add a shorthand syntax that's not resetting
<flackr> florian: but that's not urgent
<flackr> RESOLVED: Make position a shorthand of position-anchor and a new position-type property. The shorthand resets both.
@andruud
Copy link
Member

andruud commented May 21, 2024

<flackr> astearns: this might be worth opening another issues to discover whether the pitfalls are better or worse

#8398

@tabatkins
Copy link
Member

Reopening this issue, as after doing some implementation exploration we think this is harder than originally assumed. We've also come to somewhat disagree with the original motivation entirely.

First, see #8398 (comment) for the details of what we need to do to safely shorthandify a legacy property. It's definitely not generally safe to do so, and we'll have to do something special for a property that's been a longhand as long as position has.

(I think we want to shorthandify position eventually anyway, regardless of what we're doing in Anchor Positioning. position-container, at least, is very obviously something that should be part of the position "shorthand". So this is a problem we'll need to solve, regardless of what we decide about position-anchor.)

Second, the main motivation for making position-anchor a longhand of position is just the expectation that, since position is its prefix, you'll expect them to have a longhand/shorthand relationship. This isn't an unreasonable expectation, but after reviewing the full list of properties, this expectation is actually broken a lot more than I thought it was:

List of `foo` vs `foo-*` properties that are *not* shorthand/longhand pairs:
  • border (vs border-image, border-boundary, border-collapse, border-clip)
  • color (vs color-adjust, color-interpolation, color-rendering, color-scheme)
  • contain (vs contain-intrinsic-*)
  • content (vs content-visibility)
  • flex (vs flex-direction/flow/wrap)
  • font (vs font-palette, font-synthesis)
  • grid (vs grid-row/etc)
  • margin (vs margin-trim)
  • overflow (vs overflow-anchor, overflow-clip-margin, overflow-wrap)
  • position (vs position-try, position-visibility)
  • shape from Round Display (vs shape-* from Shapes)
  • transform (vs transform-box, transform-origin, transform-style)

(Obtained by visually scanning https://drafts.csswg.org/indexes/#properties.)

(Notably, there are several other position-* properties in Anchor Positioning that we're not planning to make part of the position shorthand; I'm not entirely clear why position-anchor, specifically, is requested here.)

Usability-wise, tho, I think we actually don't want these to be set together. If you switch from position: absolute to position: fixed, for example, it's not clear that you'll generally want to reset position-anchor as well. This is especially the case as a reset-only longhand.

Like, there's four cases that you can fall in when switching from position: absolute to position: fixed (where the absolute comes from less specific general styles, and the fixed is intended to override it in a specific case):

  1. You didn't have a default anchor under absolute but want to add one under fixed: you set position: fixed; position-anchor: --foo; whether it's a shorthand or not.
  2. You had a default anchor under absolute and want a different default anchor under fixed: you set position: fixed; position-anchor: --foo; whether it's a shorthand or not.
  3. You had a default anchor under absolute and want the same default anchor under fixed: you have to set position: fixed; position-anchor: --bar; if it's a shorthand; you only have to set position: fixed if they're unrelated.
  4. You had a default anchor under absolute and you don't want a default anchor under fixed: you get to only set position: fixed if it's a shorthand; you have to set position: fixed; position-anchor: none; if they're unrelated.

So 1 and 2 don't care, 3 is slightly better if they're unrelated, and 4 is slightly better if they're related. Between 3 and 4, I think 3 is more likely to come up, if such scenarios happen at all. If you just aren't using a default anchor (for 4), you can generally just not mention it and it'll act like the same as not having one at all.

(Contrast this with position-container, which likely does want to be set differently if you're switching between abspos and fixpos, I think. It's very appropriate to be reset by position, imo.)


So, we'd like to revert this resolution, and instead resolve that position-anchor is not intended to be part of a future position shorthand. This also gives us more time to resolve the general issues with shorthandifying a long-standing non-shorthand property, as explored in #8398, rather than having to rush that issue just for this one case.

@fantasai
Copy link
Collaborator Author

Let me walk through your examples with the position shorthand option:

  1. You set position: fixed --foo; in a single declaration.
  2. You set position: fixed --foo; in a single declaration.
  3. You set position-type: fixed to switch from absolute to fixed without changing the anchor.
  4. You set position: fixed which clears out all positioning properties (other than inset).

Shorthanding lets you reset everything or flip only the positioning type, whichever is appropriate to your use case.

This also gives us more time to resolve the general issues with shorthandifying a long-standing non-shorthand property, as explored in #8398

Let's dig into that issue. It's been looming over these discussions long enough.

@tabatkins
Copy link
Member

Let's set aside the "can we even shorthandify position at this point" question. Assume we can, for the moment - I still think we shouldn't put position-anchor into it.

Looking at the wider design space, what things we'll want to put into position - at minimum, position-container will be included, which also has a dashed-ident value. So fixpos and abspos will want to be able to take two dashed-idents, and we need to tell them apart somehow. We've only got a few examples of that in shorthands so far, and they're generally not very good. For example, font separates the font-size from the line-height by requiring font-size to come first and using a / before the line-height (even if the font-size is omitted), like font: / 1.2em to set just the line-height to 1.2em.

And stickypos wants to be able to use position-container, but doesn't have a reasonable use for position-anchor; we'll want consistent syntaxes between the two keywords, so presumably position-container would be the first dashed-ident, and we'll need position-anchor to come second and hold the slash or whatever. This would make it position: fixed / --foo;, which feels weirder, since position-anchor is the more commonly useful value than position-container for abspos/fixpos; position: fixed --bar; would be easier to write but not used as much, most likely.

Beyond this smaller issue, the larger suite of anchor-pos-related properties that could potentially be folded into position also only make sense for abspos/fixpos, again meaning that we have divergent grammars for the shorthand between abspos/fixpos and relpos/stickypos. Most of our shorthands are very simple, just "any of the longhands, in any order" as a syntax; the few exceptions we have that have more specific grammars are, generally speaking, hard to use. (There's a few exceptions, like grid-template which benefits from having a specific grammar that mixes things in a 2d relationship. But font is definitely an examplar of this problem, despite being close to just being "all the longhands".)

If we were designing position today, this wouldn't be an issue, because we would never have packaged abspos/fixpos with relpos/stickypos in the first place; the two sets are completely different features. But we're stuck with the legacy mistakes we've made, and I think they constrain us sufficiently that position shouldn't become a shorthand, at least for the anchor pos properties (and generally anything that applies only to abspos/fixpos).


If the shorthanding compat issues are resolvable such that we could shorthandify position, I think it's reasonable to set position-container in it. That applies to abspos/fixpos and stickypos; its lack of applicability to relpos weighs comparatively less, imo, since relpos basically doesn't do anything anyway.

I could even see us introducing a new shorthand, designed just for abspos/fixpos, which sets position and the anchor-pos properties all together. Since it wouldn't be able to set the relpos/stickypos values, it woudln't have to worry about designing for it, so we could optimize the syntax for our use-case well. No idea what we would call it, tho. ^_^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment