[csswg-drafts] Custom mathematical functions (#7490)

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

== Custom mathematical functions ==
@tabatkins mentioned the idea of custom mathematical functions in a [comment on the custom units issue](https://github.com/w3c/csswg-drafts/issues/7379#issuecomment-1170415284):

> Like, pretend for a moment that we have simple custom functions, like:
> 
> ```css
> @custom-function --fluid(--value) {
>   arg-syntax: --value "<number>";
>   result: clamp(1rem, var(--value) * 1vw, var(--value) * 1rem);
> }
> ```

This seems too good to not follow up on. Custom functions would make it possible to write more readable css with less repetition. 

### Background
We can already increase readability and reduce repetition of mathematical expressions by using function like custom properties, as @mirisuzanne describes in [her excellent article on CSS Custom Properties In The Cascade](https://www.smashingmagazine.com/2019/07/css-custom-properties-cascade/). _This is available in browsers today_. 

There are however limits to what we can do with function-like custom properties, and there are issues with their readability.

**Example**
The following expression returns 0% at a minimum viewport size of 375px, and 100% at a maximum viewport size of 1920px. 

```css
clamp(0%, 100% * (100vw - 375px) / (1920px - 375px), 100%)
```

We could give this expression semantic meaning and reuse it almost everywhere by declaring it as the value of a custom property:

```css
* {
    --min-width: 0px;
    --max-width: 2560px;
    --fluid-ratio: clamp(0%, 100% * (100vw - var(--min-width)) / (var(--max-width) - var(--min-width)), 100%);
}
```

This custom property could then be used with "arguments" where needed: 

```css
p {
  --min-width: 375px;
  --max-width: 1920px;
  font-size: mix(var(--fluid-ratio), 1rem, 1.25rem);
}
```
This is great, and should work in browsers today (except for divide by unit, that is specified in css-units-4 but not supported yet).

There are some limitations to this approach:

1. It's not possible to read from the rule that `--min-width` and `--max-width` are arguments for `--fluid-ratio`, nor that `--fluid-ratio` is a function like custom property. 
2. We would run into trouble if we wanted to reuse the same "function" with separate parameters.

```css
p {
  /* This would not work. (Arguably a constructed example) */
  --min-width: 375px;
  --max-width: 1920px;
  font-size: mix(var(--fluid-ratio), 1rem, 1.25rem);

  --min-width: 375px;
  --max-width: 700px;
  padding: mix(var(--fluid-ratio), 1rem, 2rem);
}
```

### Proposal

Add syntax for custom mathematical functions. The syntax could follow the example from @tabatkins comment with an at-rule to declare the function and the syntax of its arguments:

```css
@custom-function --fluid-ratio(--min-width, --max-width) {
   arg-syntax: --min-width "<length>", --max-width "<length>";
   result: clamp(0%, 100% * (100vw - arg(--min-width)) / (arg(--max-width) - arg(--min-width)), 100%);
} 
```

The custom function could then be used where mathematical expressions can be used:
```css
p {
  font-size: mix(--fluid-ratio(375px, 1920px), 1rem, 1.25rem);
  padding: mix(--fluid-ratio(375px, 700px), 1rem, 2rem);
}
```

There are probably many reasons why this would be annoying or impossible to implement, but hopefully there's smarter people than me out there that can come up with a way to solve custom functions. 


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


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

Received on Tuesday, 12 July 2022 18:24:19 UTC