To [=register=] a [=custom highlight=],
invoke the
set
method of the [=highlight registry=]
which will run [[webidl#js-map-set|the steps for a built-in maplike set function]],
with the [=highlight registry=] as the
this
value,
the passed-in [=custom highlight name=] as
keyArg,
and the passed-in highlight as
valueArg.
The
custom highlight name assigned to a [=custom highlight=] when it is [=registered=]
is used to identify the highlight during styling (see [[#styling-highlights]]).
Note: When registering a [=custom highlight=],
authors are advised to use a [=custom highlight name=] that is a valid CSS [=identifier=].
Using a name that is not a valid identifier can make the highlight hard,
and in some cases impossible, to style via CSS.
Note: It is possible to [=register=] a [=custom highlight=] with more than one [=custom highlight name=].
However, using more than one name to style a highlight
will assign the highlight multiple different sets of styles,
without a way to control the stacking order of conflicting styles
within these sets during [[#painting|painting]].
This could be limiting for authors and could cause confusing painting behavior
(see the
example below for more context).
Therefore,
authors are advised to only use one name per highlight during styling.
abc
In the example above,
the same [=custom highlight=] object is [=registered=] under the names
foo
and
bar
.
Since each of the [=style rules=] target the same highlight and have the same [=specificity=],
authors might expect the last rule to win in cascading order
and the highlighted content to be green.
However, each highlight name gets an independent set of highlight styles,
and the highlight will be painted once per name.
In this case, because
foo
was registered before
bar
,
the highlight will be first painted with
foo
's color (green)
and then with
bar
's color (red).
As a result, the highlighted content will appear red.
Styling Custom Highlights
The Custom Highlight Pseudo-element: ''::highlight()''
The ''::highlight()'' pseudo-element
(also known as the
custom highlight pseudo-element)
represents the portion of a document that
is being [=contained=] or [=partially contained=]
in all the [=ranges=] of the [=registered=] [=custom highlight=]
with the [=custom highlight name=] specified as its argument.
Processing Model
Applicable Properties
[=Custom highlight pseudo-elements=],
like the built-in [=highlight pseudo-elements=],
can only be styled with a limited set of properties.
See [[css-pseudo-4#highlight-styling]] for the full list.
Default Styles
UAs must not define any default UA stylesheet rules
or
paired default highlight colors
for any [=custom highlight pseudo-elements=].
In other words,
when some content is highlighted by an unstyled custom highlight,
its presentation must not change.
Cascading and Inheritance
The [=cascading=] and [=inheritance=] of [=custom highlight pseudo-elements=] is handled
identically to that of the built-in [=highlight pseudo-elements=],
as defined in [[css-pseudo-4#highlight-cascade]].
Painting
The painting of [=custom highlights=] is also handled
identically to that of the built-in [=highlight pseudo-elements=],
as specified in
[[css-pseudo-4#highlight-bounds]] and [[css-pseudo-4#highlight-painting]],
with the following clarifications:
-
[=Collapsed=] [=ranges=] are not rendered.
-
Overlapping [=ranges=] within a single [=custom highlight=] are rendered
as if a single range representing the union of the overlapping ones
had been specified.
The following example renders in a single highlight with semi-transparent blue background,
not two overlapping ones which can be seen through each other.
Lorem Ipsum.
In other words, this rendering would be correct:
Lorem Ipsum.
However, this one would be incorrect:
Lorem Ipsum.
-
The [=highlight overlays=] of the [=custom highlights=]
are below those of the built-in [=highlight pseudo-elements=]
in the stacking order described in [[css-pseudo-4#highlight-painting]].
-
The relative stacking order of the [=highlight overlays=]
of multiple [=custom highlights=]
is defined by their [=priority=]
(see [[#priorities]]).
Priority of Overlapping Highlights
A [=custom highlight=]'s {{Highlight/priority}} attribute
defines its
priority.
This is used to determine the stacking order of the corresponding [=highlight overlay=]
during painting operations (see [[#painting]]).
A higher [=priority=] results in being above in the stacking order.
A custom highlight will have a default numerical priority of 0
if its {{Highlight/priority}} attribute has not been explicitly set.
When two or more [=custom highlights=] have the same numerical priority,
the one most recently [=registered=] has the higher effective [=priority=].
Some text
As there are no priorities set
(i.e. there is a tie between
h1
and
h2
),
the custom highlights' styles are stacked
in order of insertion into the [=highlight registry=].
The rendered results will have "Som" with blue text on yellow background,
"e t" with blue text on orange background,
and "ext" with the default color on orange background.
Some text
Setting
h1.priority = 1;
would cause
h1
to stack higher than
h2
,
which would result in "Some t" being blue on yellow,
and "ext" being default color on orange.
Some text
Highlight types
A [=custom highlight=]'s {{Highlight/type}} attribute is used by authors
to specify the semantic meaning of the highlight.
This allows assistive technologies to include this meaning
when exposing the highlight to users.
A custom highlight will have a default type of {{HighlightType/highlight}}
if its {{Highlight/type}} attribute has not been explicitly set.
Note: Authors are advised to set a [=custom highlight=]'s {{Highlight/type}} to {{HighlightType/spelling-error}}
when that [=custom highlight=] is being used to emphasize misspelled content.
Authors are advised to set a [=custom highlight=]'s {{Highlight/type}} to {{HighlightType/grammar-error}}
when that [=custom highlight=] is being used to emphasize content that is grammatically incorrect.
For all other use cases {{Highlight/type}} is best left as {{HighlightType/highlight}}.
UAs should make [=custom highlight=]s available to assistive technologies.
When exposing a highlight using a given platform accessibility API,
UAs should expose the semantic meaning of the highlight
as specified by its {{Highlight/type}} attribute
with as much specificity as possible for that accessibility API.
Note: For example,
if a platform accessibility API has the capability to express spelling errors and grammar errors specifically,
then UAs is expected to use these capabilities to convey the semantics for highlights
with {{HighlightType/spelling-error}} and {{HighlightType/spelling-error}}.
If an accessibility API only has the capability to express spelling errors,
then UAs would be expected to convey both highlights with {{HighlightType/spelling-error}}
and with {{HighlightType/grammar-error}} using spelling error semantics.
If an accessibility API has support for expressing neither spelling errors nor grammar errors,
then UAs would expose all highlights as generic {{HighlightType/highlight}} regardless of their actual {{Highlight/type}}.
Note: This initial set of types was chosen
because they are expected to be popular use cases for Highlight API
and there is some existing support for expressing their semantics in platform accessibility APIs today.
Accessibility APIs currently don't have any way to express the specific semantics
of other expected Highlight API use cases.
More types could later be added to {{HighlightType}}
as accessibility APIs gain support for expressing additional popular use cases of Highlight API.
Responding to Changes
Repaints
The addition or removal
of a [=custom highlight=] in the [=highlight registry=],
or of a [=range=] in a [=registered=] [=custom highlight=],
must cause the user agent to reevaluate the rendering,
and to repaint if appropriate.
The user agent must also repaint highlights as needed
in response to changes by the author
to the {{Highlight/priority}},
or to the [=boundary points=] of {{Range}}s
of a [=registered=] [=custom highlight=].
This repaint is asynchronous, and the APIs mentioned above must not block while waiting for the
repaint to happen.
Range Updating and Invalidation
Authors can build [=custom highlights=] using either {{Range}}s or {{StaticRange}}s.
The resulting [=custom highlight=] represents the same parts of the document,
and can be styled identically.
However, the behavior is different
in case the underlying document is modified.
{{Range}}s are [=live ranges=].
The user agent will adjust the [=boundary points=] of {{Range}}s
in response to DOM changes overlapping the range or at its boundary,
and [[#repaint|repaint]] accordingly.
[=Boundary points=] of [=live ranges=] can also be changed
by the author.
On the other hand,
the user agent must not adjust the [=boundary points=] of {{StaticRange}}s
in response to DOM changes,
nor can they be modified by the author after creation.
The user agent is expected to store the actual {{StaticRange}}s, rather than backing
them up with live {{Range}}s.
Updating all {{Range}} objects as the DOM is modified
has a significant performance cost.
Authors who intend to observe DOM changes and react to them
by adjusting or recreating the ranges in their [=custom highlights=]
are strongly encouraged to use {{StaticRange}}s
in order to avoid this costly but unnecessary step.
Conversely, authors who use {{StaticRange}}s
should observe and react to DOM changes,
by discarding stale [=ranges=] or [=custom highlights=]
and recreating new ones.
When computing how to render a document,
if [=start node=] or [=end node=] of any [=range=]
in the [=highlight registry=] associated with that document's window
refer to a {{Node}} whose [=shadow-including root=] is not that document,
the user agent must ignore that [=range=].
If any {{StaticRange}} in the [=highlight registry=] associated with that document's window
is not
valid,
the user agent must ignore that [=range=].
Interacting with Custom Highlights
The {{highlightsFromPoint}}(
x,
y,
options) method allows developers to build scenarios
involving user interaction with [=custom highlights=]. The method returns a [=sequence=] containing the [=custom highlights=]
at a given
x,
y coordinate. The [=custom highlights=] are listed in this [=sequence=] in
descending [=priority=] order.
By default, [=custom highlights=] in a [=shadow tree=] are not returned, but the developer has the possibility to pass in
an optional
options [=dictionary=] with a
shadowRoots property containing a [=sequence=] of {{ShadowRoot}}
objects. [=custom highlights|Highlights=] contained within a [=shadow tree=] provided in this way will be returned.
The following example shows a way to use {{highlightsFromPoint}} to interact with mouse click [=event|events=].
abc
The code above will display the following styled text, note that "b" is affected by both [=custom highlight|highlights=]
h1 and
h2, whereas "a" is only affected by
h1:
abc
In this example there's an [=event listener=] set on click [=event|events=] that logs the [=custom highlights=]
present at the point where the click was made.
The following [=sequence|sequences=] are some examples of what will be printed to console after a click:
*
[ h1 ]
, if the user clicks on character "a".
*
[ h2, h1 ]
, if the user clicks on character "b",
as
h2 has higher priority than
h1.
*
[]
, if the user clicks on character "c".
The method {{highlightsFromPoint}} is defined as part of the {{HighlightRegistry}} interface as follows:
partial interface HighlightRegistry {
sequence<Highlight> highlightsFromPoint(float x, float y, optional HighlightsFromPointOptions options = {});
};
dictionary HighlightsFromPointOptions {
sequence<ShadowRoot> shadowRoots = [];
};
The
highlightsFromPoint(x, y, options)
method must return the result of running these steps:
1. If any of the following are true, return the empty [=sequence=]:
*
x is negative
*
y is negative
*
x is greater than the
viewport width excluding the size of a rendered scroll bar (if any)
*
y is greater than the
viewport height excluding the size of a rendered scroll bar (if any)
1. Otherwise, return a [=sequence=] of [=custom highlights=] given by ordering the highlights contained in this {{HighlightRegistry}} in descending order of [=priority=],
including only those highlights that contain at least one {{AbstractRange}}
abstractRange that satisfies the following:
* Let
range be a {{Range}} object whose [=start node=] and [=end node=] are set to
abstractRange's [=start node=] and [=end node=] respectively,
and [=start offset=] and [=end offset=] are set to
abstractRange's [=start offset=] and [=end offset=] respectively.
* The coordinates
x,
y fall inside at least one of the {{DOMRect}}s returned by calling {{Range/getClientRects()}} on
range.
Note: The specifics of hit testing are out of scope of this
specification and therefore the exact details of
{{highlightsFromPoint()}} are therefore too. Hit testing
will hopefully be defined in a future revision of CSS or HTML.
* The
range's {{commonAncestorContainer}} is not in a [=shadow tree=] or is in a [=shadow tree=] whose
[=shadow root=] is [=list/contains|contained by=] by
options.
shadowRoots.
Event Handling
Issue: Section on Events TBD, based on https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/highlight/events-explainer.md
Issue: should custom highlights have a dedicated event handling mechanism,
or should that be added to pseudo-elements in general?
Appendix A. Privacy Considerations
This section is non-normative.
This specification is not thought to introduce any new privacy concern.
Anyone suspecting that this is not accurate is encouraged
to get in touch with the CSS Working Group or the co-editors.
Appendix B. Security Considerations
This section is non-normative.
This specification is not thought to introduce any new security concern.
Anyone suspecting that this is not accurate is encouraged
to get in touch with the CSS Working Group or the co-editors.
Appendix C. Acknowledgements
This section is non-normative.
Issue: Acknowledge people (other than editors) who deserve credit for this.
Appendix D. Changes
This section is non-normative.
In addition to various editorial improvements and minor tweaks,
the main changes are:
* Added a {{HighlightRegistry/highlightsFromPoint}} method to
{{HighlightRegistry}}.
(See
Issue 7513)
* Specified that highlight repainting has to be done asynchronously.
(See
Issue 6987)
* Clarify that UAs cannot specify paired default highlight colors for custom highlights.
(See
Issue 6665)
* Clarify that there is no restriction on custom highlights crossing containment boundaries.
(See
Issue 4598)
* Added an I18N warning about placement of [=range=] endpoints in the middle of a
[=grapheme=] or [=supplementary character=].
In addition to various editorial improvements and minor tweaks,
the main changes are:
* Renamed
HighlightsRegister
to {{HighlightRegistry}}
* Removed the redundant
add()
method from {{HighlightRegistry}}.
(See
Issue 6092)
* Make custom highlight overlays stack below native highlight overlays.
(See
Issue 4595)
* Handle highlight priority with integers rather than floats.
(See
Issue 4592)
* Define the default value for highlight priority to be 0.
(See
Issue 6136)
* Made HighlightRegistry maplike (rather than setlike)
and remove
name
property from Highlight.
(See
Issue 5910)
* Clarified that ranges from the wrong window are not painted.
(See
Issue 6417)
* Specify that custom highlights have no UA styles.
(See
Issue 6375)
* Deferred to the [[DOM]] specification for range invalidation
(See
Issue 4597)
* Added a {{Highlight/type}} attribute to {{Highlight}}
to give clearer semantics to different highlights,
in support of exposing highlights to accessibility tools.
(See
Issue 6498)
There have been only editorial changes since the
22 October 2020 Working Draft;
see
diffs.