下記の HTML を用意します。
<div id="t1">0123456789</div>
JavaScript で上記のテキストノードに対してレンジを生成し、new Highlight()
でハイライトオブジェクトを生成し、CSS.highlights.set()
でハイライト名とハイライトオブジェクトを紐づけます。
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()
でスタイルを割り当てます。
::highlight(my-highlight) { background-color: #fbb; }
結果は下記の様になります。
下記の様に、Highlight()
には複数のレンジを指定することができます。
<div id="t1">0123456789</div> <div id="t2">0123456789</div>
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);
レンジは、下記の様に複数の要素にまたがって指定することもできます。
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);
::highlight() { ... }
には下記の限られたCSSプロパティしか指定できません。
color
background-color
text-decoration
text-underline-position
text-underline-offset
text-shadow
fill-color
(SVG)
stroke-color
(SVG)
stroke-width
(SVG)
MDN には下記のような入力文字列を検索してハイライトするサンプルが掲載されています。
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())); });
::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.