Home >Web Front-end >CSS Tutorial >CSS Custom Highlight API: A First Look

CSS Custom Highlight API: A First Look

Joseph Gordon-Levitt
Joseph Gordon-LevittOriginal
2025-03-14 11:05:09610browse

CSS Custom Highlight API: A First Look

Web text styling has always been the focus of developers. What is expected is the emergence of the CSS Custom Highlight API, which will revolutionize web text scope styling.

For example, text editing software such as Google Docs, Word, or Dropbox Paper detects spelling and grammatical errors and displays wavy lines below to prompt the user. Code editors such as VS Code also use similar methods for code errors.

Another common use case for text highlighting is the search and highlighting function. When the user enters text in the input box, the page will search for matching results and highlight them. Now, you can try pressing Ctrl/⌘ F in your browser and enter some of the text in this article.

Browsers usually handle these styles automatically. Editable area (e.g. ) will automatically display misspelled wavy lines. The Find command will automatically highlight the found text.

But what if we want to do this styling ourselves? How to implement this on a web page has long been a common problem, and it can waste a lot of time for many people.

This is not a simple puzzle. We don't just use class<span></span> Tags wrap text and apply some CSS. In fact, this requires the ability to correctly highlight multiple text ranges across any complex DOM tree and possibly across the boundaries of DOM elements.

There are two common ways to solve this problem:

  1. Styled text range pseudo-elements, and
  2. Create your own text highlighting system.

Let's first review both approaches and then see how the upcoming CSS Custom Highlight API changes all of this.

Method 1: Styleable text range

The most famous range of stylizable texts may be user-chosen. When you use pointing to the device to select text on the web page, a Selection object is automatically created. In fact, now try selecting the text on this page and then run document.getSelection() in the DevTools console. You should see the location information for the selected text.

It turns out that you can also programmatically create text selections via JavaScript. Here is an example:

 // First, create a Range object.
const range = new Range();

// and set its start and end positions.
range.setStart(parentNode, startOffset);
range.setEnd(parentNode, endOffset);

// Then, set the current selection to this range.
document.getSelection().removeAllRanges();
document.getSelection().addRange(range);

The last piece of the puzzle is to style this range. CSS has a pseudo-element called ::selection that does this, and it is supported in all browsers.

 ::selection {
  background-color: #f06;
  color: white;
}

Here is an example of using this technique to highlight all words in the page in turn:

In addition to ::selection pseudo-element, there are many other pseudo-elements:

  • ::target-text Select the text that has been scrolled to in the browser (browsers that support scrolling to text function). (MDN)
  • ::spelling-error Select text marked with the browser as containing the typo. (MDN)
  • ::grammar-error Select text marked by the browser as containing syntax errors. (MDN)

Unfortunately, browser support here is not very good, and although these scopes themselves are useful, they cannot be used to style custom text snippets – only predefined text snippets from the browser.

Therefore, user text selection is good because it is relatively easy to implement and does not change the DOM of the page. In fact, a Range object is essentially the coordinates of paragraphs in the page, rather than an HTML element that needs to be created to exist.

However, one major drawback is that creating a selection resets whatever the user has selected manually. Try selecting text in the above demo to test this. You will see that when the code moves the selection to another location, it disappears.

Method 2: Custom highlighting system

If you're not using a Selection object to suit your needs, a second solution is almost the only option. This solution revolves around doing everything by yourself, using JavaScript to insert new HTML elements where you want the highlight to appear.

Unfortunately, this means more JavaScript code needs to be written and maintained, not to mention that it forces the browser to recreate the page's layout whenever the highlight changes are made. Additionally, there are some complex edge cases, such as when you want to highlight a fragment of text spanning multiple DOM elements.

Interestingly, CodeMirror and Monaco (the JavaScript text editor library that supports VS Code) have their own highlighting logic. They use a slightly different approach, where the highlighting is contained in a separate part of the DOM tree. The text line and the highlighted paragraph are rendered at two different locations in the DOM and then positioned to each other. If you check the DOM subtree containing text, it is not highlighted. In this way, highlighting can be re-rendered without affecting the text line and no new elements have to be introduced into the text line.

Overall, it feels like a browser-supported highlighting feature is missing. Some features can help solve all these shortcomings (no interfere with user text selection, support for multiple selection, simple code) and are faster than custom solutions.

Fortunately, that's what we're going to discuss here!

CSS Custom Highlight API

The CSS Custom Highlight API is a new W3C specification (currently in working draft state) that enables arbitrary text ranges to be styled from JavaScript! The method here is very similar to the user text selection technique we reviewed earlier. It provides developers with a way to create arbitrary scopes (from JavaScript) and then style them using CSS.

Create text range

The first step is to create the text range to highlight, which can be done using Range in JavaScript. So, like we do when setting the current selection:

 const range = new Range();
range.setStart(parentNode, startOffset);
range.setEnd(parentNode, endOffset);

It is worth noting that if the node passed as the first parameter is a text node or not a text node, setStart and setEnd methods work differently. For text nodes, the offset corresponds to the number of characters in the node. For other nodes, the offset corresponds to the number of children in the parent node.

It is also worth noting that setStart and setEnd are not the only ways to describe the starting and ending positions of the range. Check out other methods available on the Range class to see other options.

Create a highlight

The second step involves creating a Highlight object for the scope created in the previous step. A Highlight object can receive one or more Ranges. So if you want to highlight many text snippets in the exact same way, you should probably create a Highlight object and initialize it with all the Ranges corresponding to those text snippets.

 const highlight = new Highlight(range1, range2, ..., rangeN);

But you can also create as many Highlight objects as you want. For example, if you are building a collaborative text editor where each user gets a different text color, you can create a Highlight object for each user. Each object can then be styled differently, as we will see next.

Register Highlight

Now, the Highlight object itself does nothing. They first need to be registered in the so-called highlighting registry. This is done using the CSS Highlights API. The registry is like a map where you can register new highlights by specifying a name for the highlight, as well as delete the highlights (or even clear the entire registry).

Here is how to register a single highlight.

 CSS.highlights.set('my-custom-highlight', highlight);

where my-custom-highlight is the name you selected and highlight is the Highlight object created in the previous step.

Style highlighting

The last step is to actually style the registered highlights. This is done with the new CSS ::highlight() pseudo-element, using the name you selected when registering the Highlight object ( my-custom-highlight in our example).

 ::highlight(my-custom-highlight) {
  background-color: yellow;
  color: black;
}

It is worth noting that just like ::selection , only a portion of the CSS attributes can be used with ::highlight() pseudo-element:

  • background-color
  • caret-color
  • color
  • cursor
  • fill
  • stroke
  • stroke-width
  • text-decoration (This may only be supported in version 2 of the specification)
  • text-shadow

Update highlighting

There are several ways to update the highlighted text on the page.

For example, you can use CSS.highlights.clear() to completely clear the highlight registry and start from scratch. Alternatively, you can also update the underlying scope without recreating any objects. To do this, again use the range.setStart and range.setEnd methods (or any other Range method) and the browser will repaint the highlight.

However, the Highlight object works similarly to JavaScript Set, which means you can also add a new Range object to an existing Highlight using highlight.add(newRange) , or delete the Range using highlight.delete(existingRange) .

Third, you can also add or delete specific Highlight objects to the CSS.highlights registry. Since this API works similar to JavaScript Map, you can use set and delete to update the currently registered Highlights.

Browser support

The specifications of the CSS Custom Highlight API are relatively new and their implementation in the browser is still incomplete. So while this will be a very useful addition to the web platform, it is not quite suitable for production environments yet.

The Microsoft Edge team is currently implementing the CSS Custom Highlight API in Chromium. In fact, this feature is now available in the Canary version by enabling the experimental web platform feature flag (under about:flags). There are no clear plans for when the feature will be released in Chrome, Edge and other Chromium-based browsers, but it's already very close.

Safari 99 also supports this API, but after the experimental flags (Develop → Experimental Features → Highlight API), and the interface is slightly different because it uses a StaticRange object instead of a Range object.

Firefox does not support this API yet, but you can read Mozilla's position on this API for more information.

Demo

Speaking of Microsoft Edge, they have set up a demo where you can try out the CSS Custom Highlight API. But before trying the demo, make sure you are using Chrome or Edge Canary with the experimental web platform feature flag enabled in the about:flags page.

/button View the demo

This demonstration uses the Custom Highlight API to highlight text ranges in the page based on what you enter in the search field at the top of the page.

Once the page is loaded, the JavaScript code retrieves all text nodes in the page (using TreeWalker) and when the user types something in the search field, the code iterates over these nodes until a match is found. Then use these matches to create a Range object and highlight it using the Custom Highlight API.

Summarize

So, is the highlighting API provided by this new browser really worth it? Definitely worth it!

First, even if the CSS Custom Highlight API looks a bit complicated at first (e.g., you have to create scopes, then highlight them, and then register them, and finally style them), it is still much simpler than creating new DOM elements and inserting them in the right place.

More importantly, the browser engine can style these ranges very, very quickly.

The reason only allows a portion of CSS attributes to be used with ::highlight() pseudo-element is that this part of the attributes only contain properties that the browser can apply very effectively without recreating the layout of the page. The engine needs to do more work by inserting new DOM elements around the page to highlight the text range.

But don't believe me. Fernando Fiori was involved in the development of the API and he created this nice performance comparison demonstration. On my computer, the performance of the CSS Custom Highlight API is on average 5 times faster than the DOM-based highlighting.

As Chromium and Safari already provide experimental support, we are getting closer to what can be used in production environments. I can't wait to see the browser consistently support the Custom Highlight API and see what features this will unlock!

The above is the detailed content of CSS Custom Highlight API: A First Look. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn