[csswg-drafts] Introduce `self()` function [css-values] (#9459)

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

== Introduce `self()` function [css-values] ==
## Problem Statement

With the increasing complexity of CSS architectures and the push for more modular and declarative designs, there's a clear advantage in allowing styles to be derived based on other computed styles without relying on custom properties alone. This proposal seeks to introduce the `self()` function to fetch and compute styles based on other properties of the same selector.

## The `self()` function

The `self()` function will allow designers to fetch a specific computed property value of the same selector in which it is being used. This can reduce the reliance on custom properties for shared values between properties, and streamline the styling process.

### Use Case

<b><i>** This is just one use case among countless</i></b>

Computing the natural nested `border-radius` for a descendant of another rounded element.

### Current Approach

```css
parent {
  --br-tl: 30px;
  --br-tr: 48px;
  --br-br: 82px;
  --br-bl: 130px;
  --p-t: 20px;
  --p-b: 10px;
  --p-r: 26px;
  --p-l: 44px;
  border-radius: var(--br-tl) var(--br-tr) var(--br-br) var(--br-bl);
  padding: var(--p-t) var(--p-r) var(--p-b) var(--p-l);
  --nested-radius:
    calc(var(--br-tl) - var(--p-t))
    calc(var(--br-tr) - var(--p-r))
    calc(var(--br-br) - var(--p-b))
    calc(var(--br-bl) - var(--p-l));
}

child {
  border-radius: var(--nested-radius);
}
```

### Using `self()` function

```css
parent {
  border-radius: 30px 48px 82px 130px;
  padding: 20px 10px 26px 44px;
  --nested-radius:
    calc(self(border-top-left-radius) - self(padding-top))
    calc(self(border-top-right-radius) - self(padding-right))
    calc(self(border-bottom-right-radius) - self(padding-bottom))
    calc(self(border-bottom-left-radius) - self(padding-left));
}

child {
  border-radius: var(--nested-radius);
}
```

### With [declarative functions](https://github.com/w3c/csswg-drafts/issues/7490)

With the prospective introduction of [declarative functions](https://github.com/w3c/csswg-drafts/issues/7490) into CSS, this feature would be even more assistive, as functions could reference other properties without needing to have every related value passed as an argument to that function.

This is how that same example above could look, abstracting the logic away into a custom function so it can be re-used effectively as often as needed, only needing to declare the logic once within the function:

```css
@custom-function --get-nested-radius {
  result: calc(self(border-top-left-radius) - self(padding-top))  calc(self(border-top-right-radius) - self(padding-right)) calc(self(border-bottom-right-radius) - self(padding-bottom)) calc(self(border-bottom-left-radius) - self(padding-left));
}

parent {
  border-radius: 30px 48px 82px 130px;
  padding: 20px 10px 26px 44px;
  --nested-radius: --get-nested-radius();
}

child {
  border-radius: var(--nested-radius);
}
```

You can think about using `self()` in declarative functions similarly to how one references `this` in a prototype method in JavaScript so the function logic can reference the object itself and its other properties, like this:

```js
String.prototype.isEmpty = function() { return this.length === 0; };
```

## Handling circularity

Addressing circularity risks could be a significant challenge with this proposal. Fetching a property's value from itself or from another property that references the original property could lead to an endless loop, but I think there may be some approaches we could take to combat/prevent that.

### Example of circularity

```css
padding-left: self(padding);
padding: self(padding-left);
```

### Proposed approaches to preventing circularity issues

1. **Explicit Blocking:** If the browser detects a circular reference when computing the `self()` value, it should block the circularity and revert to the initial or default value for that property. This behavior would be similar to the way browsers handle invalid values in CSS.

2. **Limit Depth:** Implement a depth limit for the number of times `self()` can be used consecutively within a property. If this depth is reached, it defaults to the initial or default value. This can be similar to the stack overflow concept in programming, preventing endless loops.

3. **Error Handling:** CSS could introduce a new way of handling errors where, if a circular reference is detected, a specific error state is entered for that element, allowing developers to handle it appropriately.

## Conclusion

The `self()` function has the potential to streamline CSS development and make it more modular. By allowing property values to be fetched from other properties in the same selector, it reduces the overhead of using custom properties for shared values. However, care needs to be taken to handle potential circular references, ensuring the system remains robust and predictable.

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


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

Received on Wednesday, 11 October 2023 20:44:11 UTC