CSSカスタムハイライトAPI

目次

CSSカスタムハイライトAPIとは

サンプル

基本サンプル

下記の HTML を用意します。

HTML
<div id="t1">0123456789</div>

JavaScript で上記のテキストノードに対してレンジを生成し、new Highlight() でハイライトオブジェクトを生成し、CSS.highlights.set() でハイライト名とハイライトオブジェクトを紐づけます。

JavaScript
const text = document.getElementById("t1").childNodes[0];
const range = new Range();
range.setStart(text, 2);                         // テキストノードの3文字目から(0始まり)
range.setEnd(text, 8);                           // テキストノードの10文字目の前まで(0始まり)
const highlight = new Highlight(range);          // ハイライトオブジェクト
CSS.highlights.set("my-highlight", highlight);   // ハイライト名と紐づけ

上記で紐づけたハイライト名に対して、CSS の ::highlight() でスタイルを割り当てます。

CSS
::highlight(my-highlight) {
  background-color: #fbb;
}

結果は下記の様になります。

表示
0123456789

複数のレンジを使用する

下記の様に、Highlight() には複数のレンジを指定することができます。

HTML
<div id="t1">0123456789</div>
<div id="t2">0123456789</div>
JavaScript
const text1 = document.getElementById("t1").childNodes[0];
const text2 = document.getElementById("t2").childNodes[0];
const range1 = new Range();
const range2 = new Range();
range1.setStart(text1, 2);        // text1の2~5文字目の前までと
range1.setEnd(text1, 5);
range2.setStart(text2, 4);        // text2の4~7文字目の前まで
range2.setEnd(text2, 7);
const highlight = new Highlight(range1, range2);
CSS.highlights.set("my-highlight", highlight);
表示
0123456789
0123456789

複数の要素にまたがるレンジ

レンジは、下記の様に複数の要素にまたがって指定することもできます。

JavaScript
const text1 = document.getElementById("t1").childNodes[0];
const text2 = document.getElementById("t2").childNodes[0];
const range = new Range();
range.setStart(text1, 8);          // text1 の8文字目から
range.setEnd(text2, 3);            // text2 の3文字目の前まで
const highlight = new Highlight(range);
CSS.highlights.set("my-highlight", highlight);
表示
0123456789
0123456789

指定可能なCSSプロパティ

::highlight() { ... } には下記の限られたCSSプロパティしか指定できません。

MDN には下記のような入力文字列を検索してハイライトするサンプルが掲載されています。

HTML
<input type="text" id="query">
<div id="text">
<p>The Custom Highlight API extends the concept of highlight pseudo-elements (see CSS Pseudo-Elements 4 § 3 Highlight Pseudo-elements) by providing a way for web developers to style the text of arbitrary Range objects, rather than being limited to the user agent defined ::selection, ::inactive-selection, ::spelling-error, and '::grammar-error'. This is useful in a variety of scenarios, including editing frameworks that wish to implement their own selection, find-on-page over virtualized documents, multiple selection to represent online collaboration, or spellchecking frameworks.</p>
</div>
JavaScript
const query = document.getElementById("query");
const text = document.querySelector("#text");
const treeWalker = document.createTreeWalker(text, NodeFilter.SHOW_TEXT);
const allTextNodes = [];
let currentNode = treeWalker.nextNode();
while (currentNode) {
  allTextNodes.push(currentNode);
  currentNode = treeWalker.nextNode();
}
query.addEventListener("input", () => {
  if (!CSS.highlights) { return; }
  CSS.highlights.clear();
  const str = query.value.trim().toLowerCase();
  if (!str) {
    return;
  }
  const ranges = allTextNodes
    .map((el) => {
      return { el, text: el.textContent.toLowerCase() };
    })
    .map(({ text, el }) => {
      const indices = [];
      let startPos = 0;
      while (startPos < text.length) {
        const index = text.indexOf(str, startPos);
        if (index === -1) break;
        indices.push(index);
        startPos = index + str.length;
      }
      return indices.map((index) => {
        const range = new Range();
        range.setStart(el, index);
        range.setEnd(el, index + str.length);
        return range;
      });
    });
  CSS.highlights.set("search-results", new Highlight(...ranges.flat()));
});
CSS
::highlight(search-results) {
  background-color: #fbb;
}
表示

The Custom Highlight API extends the concept of highlight pseudo-elements (see CSS Pseudo-Elements 4 § 3 Highlight Pseudo-elements) by providing a way for web developers to style the text of arbitrary Range objects, rather than being limited to the user agent defined ::selection, ::inactive-selection, ::spelling-error, and '::grammar-error'. This is useful in a variety of scenarios, including editing frameworks that wish to implement their own selection, find-on-page over virtualized documents, multiple selection to represent online collaboration, or spellchecking frameworks.