[csswg-drafts] [css-values] Add a way to set longhands to the corresponding expansion of a shorthand value (#8055)

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

== [css-values] Add a way to set longhands to the corresponding expansion of a shorthand value ==
There are some ways to set longhands to values that can't be represented at specified-value time, so they just serialize as empty string. In particular:

 - [Pending-substitution values](https://drafts.csswg.org/css-variables-1/#pending-substitution-value):
    ```js
    document.body.style.margin = "var(--m)";
    document.body.style.marginTop; // "" per spec
    ```
 - Expanded `toggle()` values (see #6764)
    ```js
    document.body.style.margin = "toggle(1px, 2px)";
    document.body.style.marginTop; // "" per #6764
    ```
 - Expanded [system fonts](https://drafts.csswg.org/css-fonts-4/#font-prop)
    ```js
    document.body.style.font = "small-caption";
    document.body.style.fontFamily; // "" in Gecko, Blink, WebKit
    ```
 - Values set by a legacy shorthand with broader grammar (see #7195)
    ```js
    document.body.style.webkitBackgroundClip = "text";
    document.body.style.backgroundClip; // "" in Backgrounds L3 (presumably, see #7195)
    ```
    ```js
    document.body.style.webkitBorderImage = "100% / 1px";
    document.body.style.borderImageWidth; // "" in WebKit, since 1px forces border-width when set via -webkit-border-image
    ```

This doesn't seem ideal, since we lose round-tripping (assigning empty string in CSSOM will just remove the declaration) and it's hard to tell what the value is. All these cases have in common that the value is set from some shorthand, so `cssText` can help serializing such shorthand, but this produces poor results when some longhand has been modified afterwards (see #2515):

```js
document.body.style.cssText = "margin: var(--m); margin-top: 1px";
document.body.style.marginLeft; // "" :( and the following don't help:
document.body.style.cssText; // "margin-right: ; margin-bottom: ; margin-left: ; margin-top: 1px;"
document.body.style.margin; // ""
```

So I had an idea to address all of this: introduce `from-shorthand( <custom-ident> ';' <declaration-value>)`:

 - It's a function that can be used in all properties.
 - It's invalid if `<custom-ident>` doesn't match the name of some shorthand ASCII case-insensitively.
 - It's invalid if the referred shorthand is not a shorthand of the current property.
 - It's invalid if `<declaration-value>` is an invalid value for the referred shorthand.
 - It's invalid if it's not the only component of the current property. Or well, allow it as an argument of `mix()` or `toggle()`, and allow these as arguments of `from-shorthand()`, and nesting combinations of these global-only functions.
 - Custom properties don't have shorthands, so when used on an unregistered prop it should just be tokenized instead of resolving there.
 - At computed-value time, it basically resolves to the value that the current property would get if the referred shorthand had been set to `<declaration-value>`.
 - I'm using a `;` instead of `,` despite being unambiguous since it would get confusing when `<declaration-value>` has commas.

Then:

```js
document.body.style.margin = "var(--m)";
document.body.style.marginTop; // "from-shorthand(margin; var(--m))"
```
```js
document.body.style.margin = "toggle(1px, 2px)";
document.body.style.marginTop; // "from-shorthand(margin; toggle(1px, 2px))"
```
```js
document.body.style.font = "small-caption";
document.body.style.fontFamily; // "from-shorthand(font; small-caption)"
```
```js
document.body.style.webkitBackgroundClip = "text";
document.body.style.backgroundClip; // "from-shorthand(-webkit-background-clip; text)" in L3
```
```js
document.body.style.webkitBorderImage = "100% / 1px";
document.body.style.borderImageWidth; // "from-shorthand(-webkit-border-image; 100% / 1px)" (the 100% is discarded and may be something else)
```
```js
document.body.style.cssText = "margin: var(--m); margin-top: 1px";
document.body.style.marginLeft; // "from-shorthand(margin; var(--m))"
document.body.style.cssText; // "margin-right: from-shorthand(margin; var(--m)); margin-bottom: from-shorthand(margin; var(--m)); margin-left: from-shorthand(margin; var(--m)); margin-top: 1px;"
document.body.style.margin; // ""
```

I guess there may be compat issues in the `var()` case, but hopefully people are not relying on getting an empty string.

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


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

Received on Wednesday, 9 November 2022 21:47:00 UTC