- From: Daniil Sakhapov via GitHub <noreply@w3.org>
- Date: Mon, 07 Jul 2025 09:20:19 +0000
- To: public-css-archive@w3.org
Following the discussion, I gave this issue more thought. Please, take a look and leave a comment, especially about the table!
## Use Cases (from my head)
1. Conditional event listeners or observers: Attaching listener/observer/animation only if a pseudo-element exists and is being rendered.
2. Performance optimization: Avoid computing layout-heavy styles, if the pseudo doesn’t affect rendering.
3. Testing: Checking for the presence of visual pseudo content is valuable.
4. Conditional content generation: Dynamically {insert additional}/{change existing} content in e.g. `::before`, if it’ll actually be used.
## What should `CSSPseudoElement.exists` mean?
In most layout-related cases (e.g. `::before`, `::after`, `::marker`), "box is generated" sounds most reasonable.
For range-based and semantic pseudos (e.g. `::selection`, `::highlight`, `::cue`, `::grammar-error`, `::checkmark`), a “is active” or “has matching range” approach is better.
So, to be future proof and being able to define `CSSPseudoElement` for more pseudo-elements, I suggest:
`CSSPseudoElement.exists` to return: true / false / null:
- true -> actively present/rendered/... defined on per-pseudo-element basis.
- false -> opposite of true.
- null -> not applicable or indeterminate (e.g., author shouldn’t be relying on it).
This avoids over-promising, while still providing usefulness in most use cases.
## `CSSPseudoElement.exists` Behavior Table
| Pseudo-element | When `.exists === true` | Notes |
|------------------------|----------------------------------------------------------------------------|----------------------------------------------------------------------|
| `::before` / `::after` | `content` is non-`none` and generates a box | `false` for empty or `content: none`, `null` when no style is defined |
| `::first-line` | Element has stylable inline text | `false` for empty/non-text elements, `null` when no style is defined |
| `::first-letter` | Stylable first character present | same as ::first-letter |
| `::placeholder` | Placeholder is visible (no user input yet) | `false` when field is filled, `null` when no style is defined |
| `::selection` | There is an active selection in the element | `false` if no text is selected, `null` when no style is defined |
| `::highlight(name)` | Named Highlight intersects visible element content | `false` otherwise, `null` when no style is defined |
| `::spelling-error` | Spellchecker detects error | Depends on UA/platform support |
| `::grammar-error` | Grammar issue detected and styled | Depends on UA/platform support |
| `::marker` | Element is styled as `list-item` and marker is rendered | `false` otherwise, `null` when no style is defined |
| `::checkmark` | Control renders internal checkmark (e.g., via `appearance: auto`) | Depends on UA and platform conventions |
| `::dropdown` | Native dropdown arrow is shown | `false` otherwise, `null` when no style is defined |
| `::cue` | Active WebVTT cue is displayed | `false` otherwise, `null` when no style is defined |
| `::backdrop` | Element is modal or in fullscreen state | `false` otherwise, `null` when no style is defined |
| `::scroll-marker` | `content` is non-`none` and generates a box and `::scroll-marker-group` exists | `false` for empty or `content: none` or no `::scroll-marker-group`, `null` when no style is defined |
| `::scroll-marker-group` | Defined in style via property and pseudo style and generates a box | `false` (or `null` for consistency?) when no style is defined |
## Special / Unresolved Cases
| Pseudo | Notes |
|------------------------|---------------------------------------------------------------------------|
| `::target-text` | Possibly `true` when fragment-activated text is present |
| `::view-transition-*` | Would need clear phase-specific definitions |
| `::part(name)` | Shouldn't be represented as CSSPseudoElement probably? `true` -> shadow tree contains a matching part |
| `::slotted(selector)` | Shouldn't be represented as CSSPseudoElement probably? `true` -> one or more matching nodes are slotted |
| Unsupported pseudos | CSSPseudoElement won't be obtained for those, but just in case: `.exists === null` if pseudo not applicable in current context |
--
GitHub Notification of comment by danielsakhapov
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/12158#issuecomment-3044139876 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Monday, 7 July 2025 09:20:20 UTC