[csswg-drafts] [css-values]: support inverse-axis percentage lengths (#8360)

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

== [css-values]: support inverse-axis percentage lengths ==
Currently, percentage values on some properties (namedly `padding`, `margin`, `transform`, shapes) as are restricted to their relative axis. It is impossible to set values based on on the inverse axis. For example:

* **transform: `translateX(50%)`**. Refers only to 50% of the x-axis, with nothing available to refer to the y-axis for x-related transforms.
* **clip-path: `circle(50px at 0 100px);`**: x and y values are locked to their respective axes.

Uses:

If both x-axis (inline) and y-axis (block) axis can be referred to in the same value, we can use more complex aspect ratio enforcement than just limiting the size of the element with `aspect-ratio`.  

For example, when trying to position a circle clip-path to cover the entire containing block, it requires use of a special value `circle(closest-side)`, but this becomes impossible for polygon shapes. A diamond cutout can be written `clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);`, but only works if the containing box is square in shape, which is not a requirement for circles because `closest-side` is baked into the spec. To do this accurately, the element has to be measured over JS, tracked with ResizeObserver, and then have the values injected over inline-styles:

````css
--width: 80px; /* From JS */
--height: 200px; /* From JS */
--size: min(var(--width), var(--height));
--left: calc((var(--width) - var(--size)) / 2);
--right: calc(var(--left) + var(--size));
--top: calc((var(--height) - var(--size)) / 2);
--bottom: calc(var(--top) + var(--size));
clip-path: polygon(
    50% var(--top),
    var(--right) 50%,
    50% var(--bottom),
    var(--left) 50%
    );
````

Suppose, we use an explicit value length that allows us to get the logical height and logical width, as in `padding` and `margin`. With, as example `cb` (containing block %), and `ci` (containing inline %), the new clip-path could be written as:

````css
--size: min(50ci, 50cb);
--left: calc((100ci - var(--size)) / 2);
--right: calc(var(--left) + var(--size));
--top: calc((100cb - var(--size)) / 2);
--bottom: calc(var(--top) + var(--size));
clip-path: polygon(
    50% var(--top),
    var(--right) 50%,
    50% var(--bottom),
    var(--left) 50%
    );
````

Of note, this can be somewhat complicated because we'd be tapping into the box model, and things can be a bit wonky related to `box-sizing`. It might be possible, but you'd have to guard properties from self-referencing their own values (eg: `width: 50ci`) which can cause infinite loops. All the complexities of Container Queries would likely apply here.

--------------------------------

Another option is to extend rules that already support percentage values to optionally support an "inverse percentage", which can have the syntax `i%`. Instead of referencing its respective (primary) axis (eg: `translateX(50%)` relates to x-axis), a value can reference its inverse axis (eg: `translateX(50i%)`. It keeps whatever guards are already present and ignores any explicit rules related to the box model.

Then the clip-path can be written as:

````css
--size: min(50%, 50i%); /* Regardless of primary axis (x/y), result would be the same */
--left: calc((100% - var(--size)) / 2);
--right: calc(var(--left) + var(--size));
--top: calc((100% - var(--size)) / 2);
--bottom: calc(var(--top) + var(--size));
clip-path: polygon(
    50% var(--top),
    var(--right) 50%,
    50% var(--bottom),
    var(--left) 50%
    );
````

I am sure there other examples where being bound to one axis can make things impossible with CSS alone, but `CSS Shapes` currently the one I'm currently tackling. 

Specs:

* https://www.w3.org/TR/css-shapes/
* https://www.w3.org/TR/css-box-3/
* https://www.w3.org/TR/css-values-4/
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

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


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

Received on Wednesday, 25 January 2023 19:46:42 UTC