[csswg-drafts] [css-values-5] Proposal for a new `match()` CSS Function (#10594)

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

== [css-values-5] Proposal for a new `match()` CSS Function ==
## Abstract

The `match()` function is proposed to enhance the conditional application of styles in CSS by checking if the current element matches a specified selector. This function complements the [recently accepted](https://github.com/w3c/csswg-drafts/issues/10064#issuecomment-2165157958) new [`if()` function](https://github.com/w3c/csswg-drafts/issues/10064#issue-2182499866), providing a more semantic and readable way to handle conditional logic within CSS properties.

## Motivation

The current method of conditionally applying styles in CSS often involves the use of custom properties (variables) and mathematical operations, which can become complex and less readable. The introduction of `if()` allows for clearer boolean logic handling. However, the need to constantly check selector matches remains manually verbose. The `match()` function aims to address this by allowing a direct approach to conditionally altering styles based on selector matches.

## Syntax

```css
match(selector)
```

- **selector**: A CSS selector to check against the current element.

## Usage

The `match()` function can be used inside any CSS property value expression where conditional styles are necessary based on whether the current element matches a specified selector.

### Example 1: Basic example

```postcss
.item {
  --symbol: if(match(.favorite) ? "🧡" : "🩶");
  &::before {
    content: var(--symbol);
  }
}
```

In this example, the `--symbol` custom property is conditionally set to different emoji characters based on whether the `.item` element has the `.favorite` class.

## Comparison to existing methods

### Example 2.1: Without `if()` and `match()`

```postcss
.item {
  --symbol: "🩶";
  &::before {
    content: var(--symbol);
  }
  &.favorite {
    --symbol: "🧡";
  }
}
```

This traditional approach involves redundant code as it sets the same property (`--symbol`) in multiple places.

### Example 2.2: Using `if()` and `match()`

```postcss
.item {
  --symbol: if(match(.favorite) ? "🧡" : "🩶");
  &::before {
    content: var(--symbol);
  }
}
```

This approach reduces redundancy and centralizes the logic for setting the `--symbol` property.

## A case for boolean expressions outside `if()`

I've opened a separate proposal focused on supporting a new "boolean" custom property type, which could hypothetically be valid and type-safe even outside of `if()`. If that's accepted, an example using a math-based switch like the one below could be simplified to use boolean logic.

### Example 3.1: Using a math-based switch

This example uses a math-based switch to zero out values when a condition is not met.

```postcss
label {
  --selected: 0;
  &:has(:checked) { --selected: 1; }
  grid-template-columns: auto calc(var(--selected) * 20px);
  svg { opacity: var(--selected); }
}
```

### Example 3.2: Using `match()` and `if()`

This moves the conditions inline, but they're a bit complex, so it's not ideal that we have to repeat the conditions in both values.

```postcss
label {
  grid-template-columns: auto if(match(:has(:checked)) ? 20px : 0);
  svg { opacity: if(match(:has(:checked)) ? 1 : 0); }
}
```

### Example 3.3: Using `match()` and `if()`

Using reusable boolean values can offload some of this complexity.

```postcss
label {
  --selected: match(:has(:checked));
  grid-template-columns: auto if(var(--selected) ? 20px : 0);
  svg { opacity: if(var(--selected) ? 1 : 0); }
}
```

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


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

Received on Thursday, 18 July 2024 22:03:06 UTC