CSS Custom Highlight APIで任意の範囲のテキストをハイライトする
CSS Custom Highlight APIはDOMを変更せずに任意のテキスト範囲をハイライトする機能です。JavaScriptでRangeオブジェクトを定義し、Highlightオブジェクトとして登録後、CSSの::highlight擬似要素でスタイリングして特定の範囲をハイライトします。
はじめに
【訂正】この記事では、Firefox 140のリリースによってCSS Custom Highlight APIがBaseline入りしたと記述していますが、実際にはまだBaseline 2025の対象にはなっていませんでした(MDNではBaseline入りしているように見えます)。
Firefox 140のリリースで、CSS Custom Highlight APIがサポートされました。この新機能により、JavaScriptで定義した任意のテキスト範囲をCSSでスタイリングできるようになります。
これは、構文ハイライト・検索結果のハイライト・スペルミスの表示など、多くの用途で活用できるとても便利な機能です。
CSS Custom Highlight APIとは
CSS Custom Highlight APIは、ページ内のDOMに影響を与えることなく任意のテキスト範囲をハイライトさせるAPIです。
このAPIは::selection、::spelling-error、::grammar-error、::target-textのような擬似要素を拡張したようなもので、::highlight擬似要素を利用します。
特徴
- DOMに影響を与えることなく、任意のテキスト範囲に対してハイライト可能
- JavaScriptから動的にハイライトの追加、変更、削除が可能
- ハイライトの優先順位を設定可能
- 支援技術に対してハイライトの意味的情報を提供可能
利用方法
まず初めに、Rangeオブジェクトを使用して、ハイライトしたいテキストの範囲を定義します。
// ハイライトするテキストのElementを取得
const targetNode = document.getElementById('target-text');
// Rangeオブジェクトを作成
const range = new Range();
// テキストノードの開始位置と終了位置を設定(例では最初の2文字めまで)
range.setStart(targetNode, 0);
range.setEnd(targetNode, 2);
次に、Rangeオブジェクトを使用してHighlightオブジェクトを作成し、それをHighlightRegistryに登録します。
HighlightRegistryにはCSS.highlightsからアクセスします。
// Highlightオブジェクトを作成
const highlight = new Highlight(range);
// HighlightRegistryにHighlightオブジェクトをmy-highlightとして登録
CSS.highlights.set('my-highlight', highlight);
最後に、::highlight擬似要素を用いてmy-highlightで登録した箇所のスタイルを定義します。
::highlight(my-highlight) {
background-color: yellow;
color: black;
}
これで完了です。指定したテキスト範囲がハイライトされ、スタイルが適用されます。
12文字以降をハイライトした例
知らざるを知らずとなす、これ知るなり
APIへの理解を深める
Highlightオブジェクト
Highlightオブジェクトは、一連のRangeオブジェクトを同じハイライトを行うグループとして管理するためのものです。
オブジェクトの作成
Highlightオブジェクトは、1つ以上のRangeオブジェクトを追加して作成されます。
const highlight = new Highlight(range1, range2, range3);
複数のRangeオブジェクトを渡すことで、1つのハイライトに複数のテキスト範囲を指定できます。
オブジェクト作成後の操作
Highlightオブジェクトの作成後も、それが持つRangeオブジェクトを操作できます。
Highlightオブジェクトが持つRangeオブジェクトはsizeプロパティで確認できます。
console.log(highlight.size);
addメソッドは新たなRangeオブジェクトを追加するために使用されます。
highlight.add(newRange);
clearメソッドは、すべてのRangeオブジェクトを削除します。
highlight.clear();
deleteメソッドは、特定のRangeオブジェクトを削除します。
highlight.delete(range1);
この他にも、Setオブジェクトが持つようなentriesやforEach、keys、values、hasメソッドも利用可能です。
つまり、HighlightオブジェクトはRangeだけを持つSetオブジェクトなような振る舞いをします。
優先度の設定
複数のハイライトが重複する場合、Highlightオブジェクトのpriorityプロパティを参照して、どのハイライトが優先されるかを決定します。
const highPriorityHighlight = new Highlight(range1);
highPriorityHighlight.priority = 10;
const lowPriorityHighlight = new Highlight(range1);
lowPriorityHighlight.priority = 1;
const defaultPriorityHighlight = new Highlight(range1);
console.log(highPriorityHighlight.priority); // 10
console.log(lowPriorityHighlight.priority); // 1
console.log(defaultPriorityHighlight.priority); // 0
priorityのデフォルトは0です。上記の例では、highPriorityHighlightが最も優先され、次にlowPriorityHighlight、最後にdefaultPriorityHighlightが適用されます。
優先度の異なるハイライトの例
Imagination is more important than knowledge
上記の例では、Imaginationの部分に3つのハイライトを定義しています。一つは優先度1で青色、もう一つは優先度1で黄色、最後は優先度0で赤色です。
優先度が同じ場合はCSS.highlightsに後から登録されたハイライトが優先されます。
今回は青色と黄色が同じ優先度、登録順は青色->黄色->赤色の順ですので、黄色が優先されて表示されています。
ハイライトの意味を指定
typeプロパティはハイライトの意味を指定できます。これにより、支援技術がハイライトの内容を理解しやすくなります。
const spellErrorHighlight = new Highlight(errorRange);
spellErrorHighlight.type = 'spelling-error';
typeにはデフォルトのhighlightの他に、spelling-errorやgrammar-errorなどの値を指定できます。
highlightには特別な意味がありません。spelling-errorはスペルミス、grammar-errorは文法エラーを意味します。
grammar-errorでハイライトした例
食べれる
HighlightRegistry
HighlightRegistryは、複数のHighlightオブジェクトを管理するためのオブジェクトでCSSオブジェクトに静的に組み込まれています。
HighlightオブジェクトがSetオブジェクトのような振る舞いをするのに対して、HighlightRegistryはMapオブジェクトのような振る舞いをします。
keyはハイライトの名前で、valueはHighlightオブジェクトです。
CSS.highlights.set('my-highlight', highlight); // Highlightオブジェクトを登録
CSS.highlights.get('my-highlight'); // Highlightオブジェクトを取得
CSS.highlights.has('my-highlight'); // Highlightオブジェクトが存在するか確認
CSS.highlights.delete('my-highlight'); // Highlightオブジェクトを削除
CSS.highlights.clear(); // すべてのHighlightオブジェクトを削除
setメソッドはHighlightRegistryオブジェクト自体を返すので連鎖的に記述することも可能です。
CSS.highlights
.set('my-highlight', highlight1)
.set('another-highlight', highlight2);
::highlight擬似要素
::highlight擬似要素は、HighlightRegistryに登録されたハイライトをCSSでスタイリングするために使用します。
::highlight(my-highlight) {
background-color: yellow;
color: black;
}
この中ではcolorとbackground-color、text-decoration、text-shadowしか、利用できないことに注意してください(-webkitから始まる一部のプロパティも利用可能です)。
おわりに
Firefox 140でのCSS Custom Highlight API対応により、柔軟で効率的なテキストハイライト機能を実装できるようになりました。
DOMを操作するような古典的な手法と比較して、パフォーマンス面でも大きなメリットがあるため利用していきたいです。