Skip to content

[css-selectors-4] ::is() functional pseudo element selector #13283

@romainmenke

Description

@romainmenke

See: #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 elements, it can also select regular elements.

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:

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

/* equivalent to: */
.foo::before {}
.foo.bar {}
:hover::is(::before, .foo) {}

/* equivalent to: */
:hover::before {}
:hover.foo {} /* itself equivalent to: `.foo:hover {}` */
::is(::before, .foo):hover {}

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

Examples from #9702 (comment)

A::before { &:hover {}}

/* equivalent to: */
::is(A::before):hover {}

/* equivalent to: */
A::before:hover {}

in contrast to:

A::before { :hover& {}}

/* equivalent to: */
:hover::is(A::before) {}

/* equivalent to: */
A:hover::before {}

:hover { ::before& {}}

/* equivalent to: */
::before::is(:hover) {}

/* equivalent to: */
::before:hover {}

in contrast to:

:hover { &::before {}}

/* equivalent to: */
::is(:hover)::before {}

/* equivalent to: */
:hover::before {}

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

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

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

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

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

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions