Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
この文書は、Selection API および選択に関連する機能の仕様の予備草案です。これは HTML specification のいくつかの古いセクションと、古い DOM Range specification の選択に関する部分を置き換えるものです。
この文書は選択のための API を定義しており、ユーザーや作成者が文書の一部を選択したり、コピー、貼り付け、その他の編集操作のための関心点を指定したりできるようにします。
このセクションは、本書の公開時点での状態を説明します。現行の W3C 出版物の一覧およびこの技術報告書の最新の改訂は、W3C technical reports index(https://www.w3.org/TR/)で確認できます。
本文書は作業中です。
この文書はWeb Editing Working Groupによって、Recommendation track を用いてWorking Draftとして公開されました。
Working Draft としての公開は、W3C およびそのメンバーによる承認を意味するものではありません。
本文書は草案であり、いつでも更新、置換、または他の文書により廃止される可能性があります。本稿を作業中以外のものとして引用することは適切ではありません。
この文書は、W3C Patent Policy の下で運営されるグループによって作成されました。 W3C は、グループの成果物に関連して行われた 特許開示の公開リスト を維持しています;そのページには特許を開示するための手順も記載されています。個人が自身が本質的請求(Essential Claim(s))を含むと考える特許について実際に知識を有する場合は、W3C 特許方針の第6節 に従って情報を開示しなければなりません。
この文書は、2023年11月03日付の W3C プロセス文書 に準拠して管理されています。
このセクションは規範的ではありません。
IE9 と Firefox 6.0a2 は、選択内の任意の範囲を許可しており、これは元々この仕様書が述べていた内容に従っています。しかし、これにより著者・実装者・仕様書の作成者が対処しなければならない不都合なコーナーケースが発生し、実際にはあまり理にかなっていません。Chrome 14 dev と Opera 11.11 は、空の要素内に選択が入らないようにするなど、選択を積極的に正規化していますが、これも著者の柔軟性を奪うという理由から良くない考え方とされています。
そこで私は、ある程度の単純化を可能にしつつも著者をあまり制限しない妥協案として仕様を変更しました。 ディスカッション を参照してください。基本的には、要素ノードやテキストノード以外の 境界点 を含む範囲や、Document から派生しない境界点を選択に含めようとすると、いくつかの場面で例外を投げる形になります。
しかし、これにより getRangeAt() は参照ではなくコピーを返す必要が生じました。また、コーナーケースで妙な故障が発生しやすくなります。特に重要なのは、DOM 変更が発生した際(たとえば、境界点のノードが親から取り除かれ、新しい境界点が非テキスト/非要素ノード内に配置される場合など)、さまざまな問題が発生する可能性があることです。さらに、従来の仕様は2つの主要な実装に合致するという利点がありましたが、新しい挙動はどの実装にも一致しませんでした。そこで元に戻しました。
バグ 15470 を参照。 IE9、Firefox 12.0a1、Chrome 17 dev、Opera Next 12.00 alpha では、範囲は初期状態で null です。
document はそれぞれ ブラウジングコンテキスト を持つ場合、 一意な selection が関連付けられます。
これは HTML 仕様の要件です。IE9 と Opera Next 12.00 alpha はこれに従うようですが、Firefox 12.0a1 と Chrome 17 dev はそうではないようです。Mozilla バグ、 WebKit バグ を参照。
この selection は、document 内のすべてのコンテンツ(ネストされた document を除く)や、その 編集ホスト を含めて、共有されなければなりません。
各 selection は、1つの range と関連付けできます。 range が selection に関連付けられていない場合、 選択状態は 空 です。選択状態は初期状態で 空 でなければなりません。
document の selection は、その document に紐づいたシングルトンオブジェクトであり、
Document.open() が呼ばれると新しいオブジェクトに置き換えられます。バグ 15470 を参照。
IE9 と Opera Next 12.00 alpha は、クリックにより後から範囲を null にできますが、Firefox 12.0a1 と Chrome 17 dev
はできません。Gecko/WebKit の動作に従います。なぜなら、getRangeAt(0) が例外を投げる可能性が減少するからです。
selection が range と関連付けられると、 仕様で別途要求されない限り、そのまま同じ range と紐づき続けなければなりません。
たとえば、DOM が範囲の境界点を変更するような形で変化した場合、またはスクリプトが範囲の境界点を変更した場合でも、
同じ range オブジェクトが引き続き selection に紐づく必要があります。ただし、ユーザーが selection を変更したりスクリプトが addRange() を呼んだ場合は、
selection は新しい range オブジェクトと関連付け直されなければなりません。
selection の range が null でなく、かつ 折りたたまれている 場合は、キャレットの位置はその range の 境界点 でなければなりません。折りたたまれていない場合、本仕様はキャレットの位置を定義しません。ユーザーエージェントは、キャレットを選択の開始・終了・その他どこに表示するかを、プラットフォームの慣習に則って決定すべきです。
各 selection には direction(forwards・ backwards・directionless)があります。ユーザーが selection を、 境界点 のいずれかをまず指定してから(例:一点をクリックし、他方へドラッグする)、もう一方を指定した場合、最初に指定した 境界点 が二番目より 後 であれば、その selection の初期状態は backwards でなければなりません。最初が 前 であれば forwards。 それ以外の場合は directionless とします。
selection の range がスクリプトで変更された場合(例:selectNode(node)
など)、
selection の direction は保持されなければなりません。
各 selection は anchor と focus も持ちます。selection の range が null のときは、 anchor、 focus のいずれも null です。 direction が forwards なら、anchor は range の start、focus は end です。 それ以外は focus が start、anchor が end です。
selection の anchor および focus は必ずしも document tree 内にある必要はありません。 同じ document の shadow tree 内にあっても構いません。
各 document、input 要素、textarea 要素 には、boolean型の has scheduled selectionchange event があり、 その初期値は false です。
Selection インターフェースは、各 document に関連付けられている selection を操作するための手段を提供します。
WebIDL[Exposed=Window]
interface Selection {
readonly attribute Node? anchorNode;
readonly attribute unsigned long anchorOffset;
readonly attribute Node? focusNode;
readonly attribute unsigned long focusOffset;
readonly attribute boolean isCollapsed;
readonly attribute unsigned long rangeCount;
readonly attribute DOMString type;
readonly attribute DOMString direction;
Range getRangeAt(unsigned long index);
undefined addRange(Range range);
undefined removeRange(Range range);
undefined removeAllRanges();
undefined empty();
sequence<StaticRange> getComposedRanges(optional GetComposedRangesOptions options = {});
undefined collapse(Node? node, optional unsigned long offset = 0);
undefined setPosition(Node? node, optional unsigned long offset = 0);
undefined collapseToStart();
undefined collapseToEnd();
undefined extend(Node node, optional unsigned long offset = 0);
undefined setBaseAndExtent(Node anchorNode, unsigned long anchorOffset, Node focusNode, unsigned long focusOffset);
undefined selectAllChildren(Node node);
undefined modify(optional DOMString alter, optional DOMString direction, optional DOMString granularity);
[CEReactions] undefined deleteFromDocument();
boolean containsNode(Node node, optional boolean allowPartialContainment = false);
stringifier;
};
dictionary GetComposedRangesOptions {
sequence<ShadowRoot> shadowRoots = [];
};
anchorNode
この属性は、anchor の node を this から返す必要があります。あるいは、anchor が null であるか、または anchor
が document
tree に存在しない場合は null を返します。
anchorOffset
この属性は、anchor の offset を this から返す必要があります。あるいは、anchor が null
であるか、または anchor が document tree に存在しない場合は
0 を返します。
focusNode
この属性は、focus の node を this から返す必要があります。あるいは、focus が null であるか、または focus が
document tree
に存在しない場合は null を返します。
focusOffset
この属性は、focus の offset を this から返す必要があります。あるいは、focus
が null であるか、または focus が document tree に存在しない場合は
0 を返します。
isCollapsed
この属性は、anchor と focus が同一である場合に限り true を返さなければなりません(両方が null
の場合を含む)。それ以外の場合は false を返します。
rangeCount
この属性は、this が empty
であるか、または focus または anchor のいずれかが document tree に存在しない場合は
0 を返し、そうでない場合は 1 を返さなければなりません。
type
この属性は、this が empty
であるか、または focus または anchor のいずれかが document tree に存在しない場合は
"None" を返す必要があります。range が collapsed である場合は
"Caret"、それ以外の場合は "Range" を返します。
direction
この属性は、this が empty
であるか、またはこの選択が directionless である場合は "none"
を返さなければなりません。選択の方向が forwards の場合は "forward"、選択の方向が backwards の場合は "backward" を返します。
getRangeAt() method
IndexSizeError
例外を、index が 0 でない場合、または this が empty である場合、あるいは focus または anchor のいずれかが document tree
に存在しない場合に投げなければなりません。そうでなければ、このオブジェクトの range への参照(コピーではなく)を返す必要があります。
addRange() method
このメソッドは次の手順に従わなければなりません:
rangeCount が 0 でない場合、これらの手順を中止します。
range を参照で追加するため、後続の getRangeAt(0) 呼び出しは同一のオブジェクトを返し、スクリプトが range
に対して行った変更は、それが取り除かれたり置換されたりするまで selection
に反映されなければなりません。具体的には、次のコードを実行すると selection は b
を含むようになります(a ではなく): var r =
document.createRange(); r.selectNode(a);
getSelection().addRange(r); r.selectNode(b);
手順2では、Chrome 58 と Edge 25 は何もしません。Firefox 51 はマルチレンジ選択を返します。少なくとも既存の range は保持します。
手順3では、Chrome 58 と Firefox 51 は参照を保存します(ここで説明されている通り)。Edge 25 はコピーを保存します。Firefox 51 は range が変更されると選択を変更します。
removeRange() method
このメソッドは、もし this の empty
にするために、その range が
range と等しい場合は関連付けを解除して this を empty にしなければなりません。そうでない場合は NotFoundError を投げます。
removeAllRanges() method
このメソッドは、this が関連付けられた range を持っている場合、その関連付けを解除して this を empty にしなければなりません。
empty() method
このメソッドは removeAllRanges() のエイリアスであり、同一の動作をしなければなりません。
getComposedRanges() method
shadowRoots"]
のいずれかの shadow-including
inclusive ancestor でない限り、次の手順を繰り返します:
shadowRoots"]
のいずれかの shadow-including
inclusive ancestor でない限り、次の手順を繰り返します:
StaticRange を含む配列を返します。
collapse() method
このメソッドは次の手順に従わなければなりません:
removeAllRanges() と同一に振る舞い、これらの手順を中止します。
DocumentType であれば、InvalidNodeTypeError
を投げてこれらの手順を中止します。
IndexSizeError
を投げてこれらの手順を中止します。
setPosition() method
このメソッドは collapse() のエイリアスであり、同一の動作をしなければなりません。
collapseToStart() method
このメソッドは、もし InvalidStateError
を投げるべき条件(すなわちこのオブジェクトが empty である場合)でなければ、新しい range を作成し、その開始と終了の両方をこのオブジェクトの range
の開始位置に設定し、作成した range を this の range に設定しなければなりません。
collapseToStart/End について、IE9 は既存の range を変更しますが、Firefox 9.0a2 と Chrome 15 dev は新しい range に置き換えます。仕様は多数派に従い、新しい range に置き換えて古い Range オブジェクトを変更しないようにしています。
collapseToEnd() method
このメソッドは、もし InvalidStateError
を投げるべき条件(すなわち this が empty である場合)でなければ、新しい range を作成し、その開始と終了の両方をこのオブジェクトの range
の終了位置に設定し、作成した range を this の range に設定しなければなりません。
extend() method
このメソッドは次の手順に従わなければなりません:
InvalidStateError
を投げてこれらの手順を中止します。
2011年1月頃にリバースエンジニアリングされた実装に基づきます。IE はサポートしておらず、Firefox(2000年以前に実装)と WebKit(2007年に実装)に依拠しています。Opera の実装は互換性がないため主に無視しています。Firefox 12.0a1 は既存の range を変更するようです。IE9 は extend() をサポートしておらず、Chrome 17 dev や Opera Next 12.00 alpha が変更または置換するかは判別できません(getRangeAt() がコピーを返すため)。それでも仕様は collapse() と一貫させるために Gecko の挙動とは異なる決定をしています。
setBaseAndExtent() method
このメソッドは次の手順に従わなければなりません:
IndexSizeError
を投げてこれらの手順を中止します。
selectAllChildren() method
このメソッドは次の手順に従わなければなりません:
DocumentType であれば、InvalidNodeTypeError
を投げてこれらの手順を中止します。
0) に設定します。
主に Firefox 9.0a2 に基づきます。引数に Document を渡すと終了オフセットが子の数ではなく 1 になるバグがありました。また、実装が DOMException と RangeException の統合に先行していたため、RangeException を投げます。
IE9 も類似の振る舞いですが不具合があります。ノードがデタッチされているか display:none の場合に "Unspecified error." を投げたり、デタッチされたコメントに対して "Invalid argument." を投げたりします。コメントを渡すとテキストノードとは異なりコメント全体を選択するようです。
Chrome 16 dev は Selection 実装に従った動作をします。表示されていないものは選択しないため、多くの場合誤っています。Opera 11.50 はテストでは何もしませんでした。
新しい range は既存のものを置換し、変異させません。これは IE9 と Firefox 12.0a1 に一致します。(Chrome 17 dev と Opera Next 12.00 alpha は getRangeAt() がコピーを返すためテスト不可。)
modify() method
このメソッドは次の手順に従わなければなりません:
各 granularity ごとに選択を拡張または移動するということが具体的に何を意味するのか、より正確に定義する必要があります。
deleteFromDocument() method
このメソッドは、もし this が empty
でなく、かつ focus と anchor の両方が document tree に存在する場合、deleteContents()
を this の range
に対して呼び出さなければなりません。そうでない場合は何もしません。
これは range を置換するのではなく実際に変異させる唯一のメソッドです。IE9 と Firefox 12.0a1 に一致します。(Chrome 17 dev と Opera Next 12.00 alpha は getRangeAt() がコピーを返すためテスト不可。)
containsNode() method
もし this が empty
であるか、または node の root がこの this に関連付けられたドキュメントでない場合、このメソッドは
false を返さなければなりません。
そうでない場合、もし allowPartialContainment が false であれば、このメソッドは、(1) 自身の range の start が
node 内の最初の境界点と等しいかそれより前であり、かつ (2) 自身の range の end が node
内の最後の境界点と等しいかそれより後である場合に限り true を返さなければなりません(視覚的に等価である場合を含む)。
もし allowPartialContainment が true であれば、このメソッドは、(1) 自身の range の start が
node 内の最後の境界点と等しいかそれより前であり、かつ (2) 自身の range の end が node
内の最初の境界点と等しいかそれより後である場合に限り true を返さなければなりません(視覚的に等価である場合を含む)。
stringifier
文字列化は、この this に関連付けられた range のレンダリングされたテキストの連結を返さなければなりません。
選択が textarea または input 要素内にある場合は、その value の選択された部分文字列を返さなければなりません。
また、Geckoの nsISelection.idl も参照してください。この仕様にはまだすべての内容が含まれているわけではなく、特に selectionLanguageChange() や containsNode() がありません。これらは、Rangeの定義で表現する方法が分からなかったため、欠落しています。
元々、SelectionインターフェースはNetscapeの機能でした。最初の実装はGecko(Firefox)に受け継がれ、後に他のブラウザーエンジンによって独立して実装されました。Netscapeの実装では、単一選択内で常に複数の範囲を許可していました。例えば、ユーザーが表の列を選択できるようにするためです。しかし、マルチレンジ選択はウェブ開発者が把握しておらず、Geckoの開発者でさえ正しく処理することはほとんどありませんでした。他のブラウザーエンジンはその機能を実装せず、さまざまな非互換な方法で選択を単一範囲に制限していました。
この仕様は、選択を最大で一つの範囲に制限する点でGecko以外のエンジンに従っていますが、APIは元々任意個数の範囲の選択を想定して設計されています。これが
removeRange() と removeAllRanges() が併存していたり、常にゼロでなければならない整数引数を取る
getRangeAt() メソッドがあったりするなどの奇妙さの理由です。
Selection
インターフェースのすべてのメンバーは、そのオブジェクトによって表される(存在すれば)range
オブジェクトに対する操作の観点から定義されています。これらの操作は、Range インターフェースで定義されるように例外を投げることがあります。したがって、Selection インターフェースのメンバーも、上記で明示的に記述された場合に加え、例外をスローする可能性があります。
この仕様は、ここで定義されるインターフェースへのエントリーポイントを提供するために、いくつかのインターフェースを拡張します。
Document
インターフェースは [HTML] で定義されています。
WebIDLpartial interface Document {
Selection? getSelection();
};
getSelection() メソッド
このメソッドは、selection を this に関連付けられた ブラウジングコンテキスト
がある場合は返し、それ以外の場合は null を返さなければなりません。
Window
インターフェースは [HTML] で定義されています。
WebIDLpartial interface Window {
Selection? getSelection();
};
getSelection() メソッド
このメソッドは、getSelection() を this の Window
の document
属性で呼び出し、その結果を返さなければなりません。
GlobalEventHandlers
インターフェースは [HTML] で定義されています。
WebIDLpartial interface mixin GlobalEventHandlers {
attribute EventHandler onselectstart;
attribute EventHandler onselectionchange;
};
onselectstart
この属性は、すべてのイベントハンドラIDL属性の
selectstart イベントに対して、すべての HTML
要素、Document オブジェクト、および Window
オブジェクトでサポートされるためのものです。
onselectionchange
この属性は、すべてのイベントハンドラIDL属性の
selectionchange イベントに対して、すべての
HTML
要素、Document オブジェクト、および Window
オブジェクトでサポートされるためのものです。
ユーザーエージェントが データを置換 または 部分文字列 を CharacterData に対して行う場合、ユーザーエージェントは、その
CharacterData の ノードドキュメント の selection に関連付けられた range を live range として更新しなければなりません。
ユーザーエージェントが Text ノード を分割する場合、ユーザーエージェントは、
Text
の ノードドキュメント の selection に関連付けられた range を live range として更新しなければなりません。
ユーザーエージェントが normalize() メソッドの手順を実行する場合、ユーザーエージェントは ノードドキュメント の selection に関連付けられた range を live range
として更新しなければなりません。
ユーザーエージェントが ノードを削除 または 挿入 する場合、ユーザーエージェントは、その ノード の ノードドキュメント の selection に関連付けられた range を live range として更新しなければなりません。
ユーザーエージェントは、selection(アクティブドキュメントに関連付けられたもの)を ユーザーが変更できるようにすべきです。ユーザーが selection を何らかの方法で変更した場合、ユーザーエージェントは range の 開始 と 終了 を適切に設定した新しい range を作成し、この selection にこの新しい range を関連付けなければなりません(既存の range を変更しないこと)、また、開始が終了より 前 あるいは等しい場合は selection の direction を forwards に、終了が開始より 前 の場合は backwards に、開始と終了がプラットフォームの慣習により順序付けできない場合は directionless に設定しなければなりません。
ユーザーエージェントは、ユーザーによるいかなる操作(例:編集不可領域のクリック)に対しても、もともと empty でなかった selection を empty にしてはなりません。
バグ15470 を参照。IE9 と Opera Next 12.00 alpha は、ユーザーがどこかをクリックすることで範囲を null にリセットできるが、Firefox 12.0a1 と Chrome 17 dev はそうではない。私は Gecko/WebKit の挙動に従います。なぜなら getRangeAt(0) が例外を投げる可能性が減るためです。
ユーザーエージェントがユーザーの操作に応答して selection に新しい範囲 newRange を関連付ける直前、境界点のノード(newRange の 開始点に対応する)で、selectstart という名前のイベント(バブルし、キャンセル可能)を発火しなければなりません。これは selection が以前 empty であったか、または以前の範囲が collapsed だった場合に限ります。
イベントがキャンセルされた場合、ユーザーエージェントは selection を変更してはなりません。
ユーザーエージェントが selection を empty に設定する場合、イベントは発火しません。
selection がその range との関連付けを解除した場合、新しい range に関連付けられた場合、または関連付けられている range の boundary point がユーザーやコンテンツスクリプトによって変異された場合、ユーザーエージェントは selectionchange イベントをスケジュール しなければなりません。
input
または
textarea
要素内でテキスト選択が提供され、その選択が範囲または direction のいずれかで変化したとき、ユーザーエージェントはその要素で selectionchange イベントをスケジュール しなければなりません。
ノード target で selectionchange イベントをスケジュールする ための手順は以下の通りです:
ノード target で selectionchange イベントを発火する 手順は以下の通りです:
非規範的と記載されたセクションだけでなく、本仕様書中のすべての執筆ガイドライン、図、例、および注記は規範的ではありません。それ以外のすべては規範的です。
この仕様書は、含まれるインターフェースを実装する ユーザーエージェント という単一製品に適用される適合基準を定義します。
この標準には既知のセキュリティ上の考慮事項はありません。
支援技術のユーザー利用を開示することによる潜在的なプライバシーリスクを軽減するため、たとえばユーザーエージェント は、ドキュメントの selection をユーザーが変更した場合、通常は selectstart や selectionchange
イベントに関連付けられるマウスやキーボードイベントをエミュレートすることを選択することがあります。
多大なる感謝を捧げます
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: