[csswg-drafts] [css-anchor-position] Nailing down the position-try-options "flip" behavior (#10049)

tabatkins has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-anchor-position] Nailing down the position-try-options "flip" behavior ==
Currently, the spec says that the `flip-block`/etc values:

> Automatically creates a [position option](https://drafts.csswg.org/css-anchor-position/#position-option) from the element’s computed style, by swapping the [margin](https://drafts.csswg.org/css-box-4/#margin-properties), [sizing](https://drafts.csswg.org/css-sizing-3/#sizing-property), [inset](https://drafts.csswg.org/css-logical-1/#inset-properties), and [self-alignment](https://drafts.csswg.org/css-align-3/#self-alignment-properties) property values among the element’s sides, and adds it to the [position options list](https://drafts.csswg.org/css-anchor-position/#position-options-list).

This isn't correct (specifically the "computed values" part), for a few reasons:

* computed value includes all the origins. Even if we ignore the animation origin, it means that UA !important rules, for example, would contribute their value to the flipped property. (but would still exist as their original form too, since they wouldn't be overrideable by the `@position-try`)
* now that we're invoking style/layout interleaving for anchor functions, the "computed value" loses the fact that there was an anchor function at all; it's just a length now. We need something before that point.

@andruud worked thru the details of what we'd probably actually want, and after discussing this with him I'm relatively convinced his idea is the right way. I think we need to specify two things:

1. The "virtual" `@position-try` generated by a flip-* keyword contains the properties specified by the `@position-try` being flipped (if there is one), flipped appropriately. It then *also* contains all the *other* position-try allowed properties, with their value being a magic internal value that's like `revert-layer`, but grabs a specified property (the one it's being flipped from). 
    
(Per other resolutions, the position-try values are applied as if they're in a final, UA-controlled cascade layer in the author origin, so this would revert to the declared value that otherwise wins the author origin.)

Aka, given:

```css
@position-try --pos {
  left: anchor(right);
  top: anchor(bottom);
}

/* Regular author styles */
div {
  position-try-options: --pos flip-inline flip-block;  
}
```

The "virtual" `@position-try` would look like:

```css
@position-try [virtual flipped --pos] {
  right: anchor(left);
  top: anchor(top);
  left: revert-layer-to(right);
  bottom: revert-layer-to(top);
  margin-top: revert-layer-to(margin-bottom);
  ...all the rest of the @position-try allowed properties...
}
```

2. The timing of *precisely* what value we're getting is potentially important here. In particular, if we're flipping the values (`anchor(right)` becoming `anchor(left)`, etc), then we want to ensure we're getting the value *after* variable substitution, but still *before* style/layout interleaving.

For example, if the author writes `--foo: anchor(right); right: var(--foo);`, then when we generate the virtual flipped position-try rule, we want to ensure it ends up acting like they'd written `left: anchor(left);`, **not** `left: var(--foo);` (which then var-substitutes to `left: anchor(right);`).

But var substitution happens to computed values, and with (1) we're working with cascaded values which precede that, so we'd have to do a special manual variable substitution, and ensure that we similarly manually applied any *other* similar transforms we ever define.

Instead of this, Anders suggests leaving the values untransformed, but specifying that the used value of `position-try-options` changes how we *interpret* the values. So in the above variable example, we *would* just flip it to `left: var(--foo);`, which subs to `left: anchor(right);`, but because we're using a flip-inline try option, it would behave as `anchor(left)`; an `align-self: start` would behave as `end`; etc.

APIs that observe the computed value won't see the position-try results; APIs that observe the the used value will see the final result after substitution, so the anchor() function itself disappears. We don't expose the used value of properties like `align-self`, so the fact that it's technically still `start` even tho it's behaving as `end` won't be visible.

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/10049 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Friday, 8 March 2024 00:02:10 UTC