w3c / csswg-drafts

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

[css-anchor-position] `position-anchor` should be defined as a longhand of `position` #10321

Open fantasai opened 5 months ago

fantasai commented 5 months ago

In https://github.com/w3c/csswg-drafts/issues/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 commented 5 months ago

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 commented 5 months ago

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

css-meeting-bot commented 5 months ago

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

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 commented 5 months ago

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

https://github.com/w3c/csswg-drafts/issues/8398

tabatkins commented 5 months ago

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 https://github.com/w3c/csswg-drafts/issues/8398#issuecomment-2123561486 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 .)

(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 commented 5 months ago

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 https://github.com/w3c/csswg-drafts/issues/8398

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

tabatkins commented 4 months ago

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. ^_^

chrishtr commented 3 months ago

Hi, this issue has received significant discussion within the Chrome team. Our conclusion:

Given all the compat risk, implementation difficulty and potential for developer confusion, Google doesn't think shorthand-ifying position is feasible or worth doing, so we object to doing so.

fantasai commented 2 months ago

WebKit would like to take some time to understand and potentially address Chrome's concerns. To that end, we're fine with leaving the spec as-is for now (position unshorthanded). But we would appreciate a more detailed explanation of the Web-compat issues with shorthanding in https://github.com/w3c/csswg-drafts/issues/8398

css-meeting-bot commented 2 months ago

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

The full IRC log of that discussion <andreubotella> TabAtkins: A while back, we resolved to make position a shorthand for position-type (setting the absolute, fixed... keywords) and position-anchor
<andreubotella> We've experimented since then, and the Chrome team would like to reverse this resolution
<andreubotella> Compat reason: we'd thought there would be a stronger compat reason to not shorthand position or other properties, but upon further review, while there's still risk, it's not that bad
<andreubotella> so we should consider shorthanding these older property
<andreubotella> we don't want to do it without a good reason because it's risky though
<TabAtkins> https://github.com/w3c/csswg-drafts/issues/10321#issuecomment-2136102979
<andreubotella> Also, after some thought, we don't agree with shorthand position being part of the position shorthand
<andreubotella> while we have a pretty strong tradition of prefix name shorthands being shorthands for properties with the same prefix, but it's not as strong as thought
<andreubotella> there's a list in that thread
<andreubotella> THe argument from langauge design is weaker than we thought, and that strengthens the argument for not making it
<andreubotella> to make a reasonable shorthand out of this, you need more complex grammar, which makes it harder to use
<astearns> q+
<andreubotella> this is in the category of properties that are adjacent to other properties but shouldn't be reset together
<astearns> ack fantasai
<andreubotella> shouldn't reset, especially if you're switching from static to fixed
<andreubotella> so we object to making position a shorthand right now, and in particular with making position anchor a part of that shorthand
<andreubotella> astearns: is the complexity of the shorthand across all the value spaces, or does it only get complex when trying to set anchor positioning values?
<andreubotella> TabAtkins: both. The first, because anchor positioning only appliies to static or fixed, ...
<andreubotella> fantasai: That's not true, if you set to sticky it would ignore all of the anchor positioning stuff
<andreubotella> TabAtkins: I think none is one of the few obvious counterexamples, but more complex distinctions we don't do too often
<astearns> ack astearns
<andreubotella> the second bit of complexity: ... and ... are custom idents, so we'd need to make them distinguishable
<TabAtkins> like, `position: absolute --foo / --bar`
<andreubotella> explicitly setting position: absolute, maybe with container in there, and then ... gives a more readable CSS in our opinion
<andreubotella> fantasai: We are interested in trying to adress Chrome's concerns. We're happy with the spec as it is now until those concerns are solved, but not happy with reverting before
<andreubotella> florian: I agree with TabAtkins about the language not being consistent with the prefix not always being the shorthand. About position resetting all of the longhands, how important is it?
<andreubotella> fantasai: it depends on whether we want a shorthand that sets it together
<andreubotella> we'd have to design that and put it out to the whole working group
<andreubotella> florian: Even if the shorthand doesn't set it together, for the things that are set by position, would you have interference from the other things set by it?
<andreubotella> If we're reverting and leaving the issue open for now, I'm good with it
<andreubotella> TabAtkins: ... and inset-area being set together ...
<andreubotella> fantasai: That's a problem with the UA stylesheet
<TabAtkins> s/inset-area/insets and position-area/
<andreubotella> RESOLVED: undo the previous resolution and not add position-anchor and position-type to the position shorthand for now
<florian> s/from the other things set by it/from the other things set by it if they don't get reset
<fantasai> scribenick: fantasai
frivoal commented 2 months ago

To me, the main question here is whether, when changing from one position-type to another, you get weird unexpected interference from other position-* if you fail to reset them. If so, we should make position a shorthand even if it doesn't include syntax to set them to explicit values, and it should at least reset them.

(Having syntax to set them is nice too, but if that's the challenge, I feel that can be dealt with later, including possibly never if that challenge turns out to be too hard to solve)

tabatkins commented 2 months ago

the main question here is whether, when changing from one position-type to another, you get weird unexpected interference from other position-* if you fail to reset them

Not particularly, no. It seems fairly unlikely, imo, that you'll switch from absolute to fixed or vice versa, which is the only case where the anchor positioning properties will continue to have an effect. If you do, I think there's a reasonable likelihood (like, roughly half the time, at least) that you do want to continue anchoring to the same element. Also if you do, there's a very high chance that you'll need to change your inset properties anyway (those seem highly unlikely to be useful with the same values in both modes), so changing more at the same time isn't unreasonable imo.

(I said in the call that changing inset and position-area together is much more likely to be the thing that we need to do, honestly. Our own devrel people keep getting confused by this issue, because the scroll adjustment relies partially on auto insets.)