---
# System prepended metadata

title: Chromium highlight pseudos meeting (2021-06)

---

# Chromium highlight pseudos meeting (2021-06)

Spec: https://drafts.csswg.org/css-pseudo-4/#highlight-pseudos

* `::selection`
* `::target-text`
* `::spelling-error`
* `::grammar-error`
* [`::highlight()`](https://drafts.csswg.org/css-highlight-api-1/#styling-highlights)

## Summary

* **::selection painting vs highlight painting**
    * The two codepaths being separate was largely a historical accident, plus some differences in their needs, like ::selection needing to be styleable and document markers needing support for multiple active ranges for each highlight.
    * Unifying these is probably a good idea, and the other highlight pseudos should benefit from ::selection’s features like suppressing text painting and clipping style changes to background rects.
    * The existing document marker system also has useful logic that should help us determine what highlights apply to any given point in the content (see NG­Highlight­Painter and Document­Marker­Vector).
    * No one has really started working on this yet, but it seems important to both Microsoft and Igalia’s current work.
* **text-decoration property**
    * Only the originating element’s decorations are recolored (to the topmost active highlight’s text color) when “lifted” to a highlight overlay (thanks fantasai!), *not* decorations introduced by “lower” active highlights.
    * The former was because it often improves legibility and not doing so often looks strange (e.g. Chromium’s default colors where selecting black text becomes white on fairly dark blue), and the latter was because the decoration colors often convey meaning (e.g. spelling and grammar errors are often identical modulo color).
        * Like all things, this can be changed if needed.
    * Squiggly lines for spelling/grammar errors suffer from going out of phase across text nodes, and wavy lines suffer from that *and* refusing to paint partial waves. Firefox seems to address these problems by starting all wavy lines from a common per-block origin, and clipping the lines to the places they are needed ([demo](https://jsfiddle.net/z39t04ay/2/), [screenshot](https://bucket.daz.cat/9a32ef82b70eddfd.png)).
    * Ordinary text decorations and spelling/grammar squigglies were separate not only for historical reasons, but because of our unique macOS behaviour of emulating platform conventions (dots with alpha gradient, and as pdr says, no partial dots).
    * Unifying wavy and non-macOS squigglies on non-macOS might be viable, but definitely not dotted and macOS dots.
* **text-shadow property**
    * Shadow clipping [was previously discussed](https://github.com/w3c/csswg-drafts/issues/3932), but there are still valid arguments for both Chromium’s “buggy” behaviour and the “fixed” behaviour [we tried to implement](https://crrev.com/c/2658617), especially with more realistic offsets (read: not like 1em 1em in my reftests).
    * Shadows are often used in a way that makes them “load-bearing” for contrast ([demo](http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=9451), [demo](http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=9452)), so making them an optional requirement is not appropriate (this applies equally to both non-highlight and highlight shadows). Either require them or drop them entirely.
    * Changing shadows from not allowed to allowed or vice versa is also like making it optional (just in the time dimension), so we should try to decide whether or not to drop it *before* it gets popular. Use counters would be useful here.
* **Highlight inheritance**
    * Blink will become the *second* impl to support this, long after Presto!
    * The spec is under [#highlight-cascade](https://drafts.csswg.org/css-pseudo-4/#highlight-cascade) because we originally wrote it as tweaked cascade, but we rewrote it as tweaked inheritance after [Emilio’s performance concerns](https://github.com/w3c/csswg-drafts/issues/2474).
    * Bo asks about the compat risk of changing ::selection style resolution this significantly. Consensus so far is that we should™ be ok given how ::selection was previously pretty much useless outside of ::selection (\*::selection) rules, and these changes won’t break existing pages that use those rules.
    * But in theory, authors could have hacked together a highlight “cascade” with “foo::selection, foo::selection *” rules (haven’t checked the compat risk of this), or even depended on the legacy behaviour where ::selection styles would reset in children?
    * The impl signals requests we’ll send to Mozilla and Apple might help inform us here.

## Highlight painting cheat sheet

* text and decorations
    * ::selection, ::target-text, ::spelling-error, ::grammar-error line-throughs in their own colors; originating element line-throughs in topmost text color
    * text in topmost color
    * ::selection, ::target-text, ::spelling-error, ::grammar-error underlines/overlines in their own colors; originating element underlines/overlines in topmost text color
* ::selection
    * text-shadow
    * background-color
* ::target-text
    * text-shadow
    * background-color
* ::spelling-error
    * text-shadow
    * background-color
* ::grammar-error
    * text-shadow
    * background-color
* originating element
    * text-shadow

text and decorations (topmost active layer only)
* line-through decorations
* text proper
* underlines and overlines
    
for each decoration type
* ::selection’s decoration
* ::target-text’s decoration
* ::spelling-error’s decoration
* ::grammar-error’s decoration
* originating element’s decoration

~~non-topmost~~ originating element decorations are also recolored to topmost currentColor, making them the same color as the text proper.

## ::selection painting vs highlight painting

Spec: https://drafts.csswg.org/css-pseudo-4/#highlight-painting

Right now there are 2 different codepaths related to highlight painting, which are still very separate despite [some initial refactoring](https://crrev.com/c/2682158):
* ::selection is [represented and painted](https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc;l=126-238;drc=5bffea289e377c7bca0c978a0eea8a75e7adeb16) as Selection­Paint­State
* the rest are represented as Document­Marker and painted [with the help of](https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc;l=263-403;drc=5bffea289e377c7bca0c978a0eea8a75e7adeb16) of Document­Marker­Painter: this includes ::target-text, ::highlight(), spelling and grammar errors, composition underline, etc.

**Discussion: should we merge these two codepaths, and if so, to what extent?**

We need to reorder paints out of NG­Highlight­Painter’s kBackground and kForeground phases and into the spec’s overlay order ([see TODO comments](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc;l=362-424;drc=095ef6693ca64c3551232a8621996d405af2403f)) for more details), but doing so can worsen bugs that have sometimes been fixed for ::selection only.

<blockquote><details>

For example, when painting `::selection`, we suppress originating text painting where highlighted and use clipping to change styles along the background edge, but neither of these are currently implemented for any other highlight pseudo.

“Suppressing” originating text like that might be tricky to implement now that there’s more than one highlight pseudo, but it’s necessary for two reasons:

1. Any combination of highlights might be active at any given point in some text, but only the topmost overlay (or originating element) at each point should paint the “text proper” (non-shadow text) and all of the decorations.
2. Each highlight can introduce its own backgrounds and shadows, and they all paint as usual where highlighted, so we need to paint text in passes, interleaving backgrounds and shadows, then text in the topmost overlay.

</details></blockquote>

Some related bugs:
* [#1171741](https://crbug.com/1171741): Selecting text causes emphasis marks to be painted twice
* [#1179938](https://crbug.com/1179938): ::target-text partially painting text with color property

## `text-decoration` property

![](https://i.imgur.com/Mi9gbHQ.png)![](https://i.imgur.com/kC7dhOQ.png)![](https://i.imgur.com/qse3V1d.png)

Text decorations have their own problems. The color change that occurs when you highlight originating decorations is to the wrong color and affects unhighlighted parts, highlights can’t add their own decorations, and a bunch more.

But highlights need to be able to add decorations, for example, so that spelling and grammar errors can add squiggly lines to text independent of any existing decorations it may or may not have (which might also have semantic importance, especially line-through).

* https://crrev.com/c/2903387 (review)
* https://crrev.com/c/2903371 (wip)

Some related bugs:

* [#932343](https://crbug.com/932343): CSS text-decoration property is totally ignored with pseudo ::selection element \[and all other highlight pseudos too]
* [#553174](https://crbug.com/553174): text-decoration incorrectly propagated to descendants of anonymous inline-table

## `text-shadow` property

![](https://i.imgur.com/znqsUyf.png)![](https://i.imgur.com/TcE5wzP.png)

Highlights are already very complex, needing lots of special cases in both style and paint, and allowing each highlight its own shadows complicates things further.

**Discussion: should we push back on this part of the spec, and try to make shadows on highlights optional, or even [drop the requirement altogether](https://twitter.com/Gankra_/status/1351020287790358530)?**

For example, decorations accumulate up through the highlight overlays for text proper (non-shadow text), but what about shadows, which also paint decorations? Note that unlike “text proper” (non-shadow text), shadows aren’t suppressed by higher-layer highlighting.

[There are also problems](https://www.azabani.com/2021/05/17/spelling-grammar.html#shadow-clipping) with how shadows on highlights interact with ::selection clipping. We found that vertical text and Draw­Looper complications made the problems impossible to fix without deeper changes.

<blockquote><details>

* https://crrev.com/c/2658617 (abandoned)
* We have since found new ideas for how to fix this, but haven’t had the time to try them
* We think there’s no practical fix without [#671438](https://crbug.com/671438): Move draw looper usage to paint ops
* …and there are many other bugs this blocks or is blocked by:
    * [skia:8672](https://bugs.chromium.org/p/skia/issues/detail?id=8672): Remove SkDrawLooper
    * [#713376](https://crbug.com/713376): Text shadow should paint behind all text decorations and text.
    * [#1172177](https://crbug.com/1172177): Erroneous viewport-size-dependent clipping of some text shadows
    * [#1176649](https://crbug.com/1176649): text-shadow paints with incorrect offset for vertical scripts in vertical writing modes
    * [#1180068](https://crbug.com/1180068): text-shadow erroneously paints over text proper in mixed upright/sideways fragments
    
</details></blockquote>

## Highlight inheritance

Spec: https://drafts.csswg.org/css-pseudo-4/#highlight-cascade

Historically this has never been supported by most impls, though Presto actually did do inheritance. For example, the p::selection background doesn’t yet apply to “world” here:

```html
<!DOCTYPE html>
<style>p::selection { background: magenta; }</style>
<p>Hello <span>world</span>!</p>
```

* https://crrev.com/c/2850068 (wip)

Some related bugs:

* [#830045](https://crbug.com/830045): Styles in ::first-letter and ::selection \[pseudo] selectors don't work together
* [#17528](https://crbug.com/17528): text containing first-letter CSS style can't be selected/searched
