[csswg-drafts] [css-selectors-4] `::is()` functional pseudo element selectors (#13283)

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

== [css-selectors-4] `::is()` functional pseudo element selectors ==
See: https://github.com/w3c/csswg-drafts/issues/9702

I've been wondering if a functional pseudo element selector might create a way forwards.
Unsure about naming, but we can always bikeshed later if this idea is worthwhile.

This `::is()` selector would work as other pseudo elements in that order in a compound matters, e.g. `:hover::is(...)` != `::is(...):hover`.

It accepts a complex selector list as its argument and is not limited to only pseudo elements.
It can select pseudo elements but isn't limited to only pseudo's.

So `::is(.foo)` works and it works exactly as `:is(.foo)`.

On its left side it matches either the originating elements or the element itself.
On its right side it matches either the pseudo element or the element itself.

For all other aspects (specificity, forgiving, ...) this new selector behaves as the existing `:is()` pseudo class.

Leaning into the special behavior of pseudo selectors (that they are combinators) might give us a way forwards with nesting. Nesting could be specified in terms of this new selector. This would not be a breaking change as any existing CSS would continue to work as it did before.

-----

Some examples:

```css
.foo::is(::before, .bar) {}

/* equivalent to: */
.foo::before {}
.foo.bar {}
```

```css
:hover::is(::before, .foo) {}

/* equivalent to: */
:hover::before {}
:hover.foo {} /* itself equivalent to: `.foo:hover {}` */
```

```css
::is(::before, .foo):hover {}

/* equivalent to: */
::before:hover {} /* never matches */
.foo:hover {} /* itself equivalent to: `:hover.foo {}` */
```


-----

Examples from https://github.com/w3c/csswg-drafts/issues/9702#issuecomment-3573406054


```css
A::before { &:hover {}}

::is(A::before):hover {} /* never matches */
```

but:

```css
A::before { :hover& {}}

:hover::is(A::before) {} /* does match! */
```

```css
:hover { ::before& {}}

::before::is(:hover) {} /* never matches */
```

but

```css
:hover { &::before {}}

::is(:hover)::before {} /* does match! */
```

------

## Using `:is()` the functional pseudo **class** with pseudo elements

`:is()` could be specified to accept pseudo elements but without any of the special behavior mentioned above.

This is still useful to filter lists of pseudo elements

```css
::before, ::after {
  &:is(::before) {}
}

/* equivalent to: */
::is(::before, ::after):is(::before) {}

/* equivalent to: */
::before:is(::before) {}
::before:is(::after) {} /* never matches */
```

```css
::before, ::after {
  :is(::before)& {}
}

/* equivalent to: */
:is(::before)::is(::before, ::after) {}

/* equivalent to: */
::before::before {} /* never matches */
::before::after {} /* never matches */
```


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


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

Received on Wednesday, 31 December 2025 06:57:28 UTC