选择 API

W3C 工作草案

关于此文档的更多详细信息
本版本:
https://www.w3.org/TR/2026/WD-selection-api-20260611/
最新发布版本:
https://www.w3.org/TR/selection-api/
最新编辑草稿:
https://w3c.github.io/selection-api/
历史:
https://www.w3.org/standards/history/selection-api/
提交历史
测试套件:
https://wpt.fyi/results/selection/
编辑:
(Apple Inc.)
反馈:
GitHub w3c/selection-api (拉取请求, 新问题, 打开的问题)

摘要

本文件是关于 Selection API 及与选择相关功能规范的初步草案。它取代了 HTML specification 的几节旧章节,以及旧 DOM Range specification 中关于选择的部分。

本文件定义了与选择相关的 API,允许用户和作者选择文档的一部分或指定用于复制、粘贴及其他编辑操作的关注点。

本文档的状态

本节描述的是本文档在其发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准和草案 索引中找到。

这是正在进行中的工作。

本文档由 Web Editing Working Group 作为 使用 推荐标准 轨道的工作草案发布。

作为 工作草案发布并不意味着 W3C 及其成员认可。

这是一份草案文档,可能随时被其他 文档更新、替换或废弃。除作为一项 正在进行中的工作之外,不应引用本文档。

本文档由一个 依据 W3C 专利 政策运作的工作组制作。 W3C 维护一份 与该组交付物相关的任何专利 披露的公开列表 ;该页面还包含 披露专利的说明。实际 知晓某项专利且认为该专利包含 基本权利要求的个人 必须依照 W3C 专利政策第 6 节披露该信息。

本文档受 2025 年 8 月 18 日 W3C 流程文档管辖。

1. 背景

本节为非规范性内容。

IE9 和 Firefox 6.0a2 允许在选择中存在任意范围,这与本规范最初的描述一致。但这会导致作者、实现者和规范作者都必须处理一些棘手的边界情况,而且这些情况其实并没有实际意义。Chrome 14 dev 和 Opera 11.11 强制规范化选择,例如不允许其位于空元素内部等,但这也被认为不是好主意,因为这限制了作者的灵活性。

所以我将规范改为一个折中方案,既允许一定简化,又不怎么限制作者。参见 讨论。基本上会在某些地方抛出异常,以防止选择包含一个不是 Element 或 Text 节点的 边界点,或选择的边界点不属于某个文档。

但这意味着 getRangeAt() 必须开始返回副本而不是引用。同时,某些边缘情况可能会导致奇怪的失败。或许最重要的是,当 DOM 发生变化时可能会出现各种问题,比如如果边界点的节点从其父节点被移除,并且变更规则会将新的边界点放在非 Text/Element 节点内部。最后,先前规定的行为具有与两个主流实现一致的优点,而新的行为却没有任何实现一致。因此,我又改回去了。

注意

参见 bug 15470。 IE9、Firefox 12.0a1、Chrome 17 dev 和 Opera Next 12.00 alpha 都使 range 初始为 null。

2. 定义

每个具有浏览 上下文的文档都有一个与之关联的唯一 选区。

注

这是 HTML 规范的一项要求。IE9 和 Opera Next 12.00 alpha 似乎遵循了这一要求,而 Firefox 12.0a1 和 Chrome 17 dev 似乎没有。 请参阅 Mozilla bug、 WebKit bug。

这一个选区必须由 文档的所有内容共享(但嵌套的文档除外),包括该 文档中的任何编辑 宿主。

每个选区都可以与单个范围关联。 当没有范围 与该选区关联时,该 选区为空。选区最初必须为 空。

注

一个文档的选区是与该文档关联的单例对象,因此当 调用 Document.open() 时,它会被替换为一个新对象。请参阅bug 15470。 IE9 和 Opera Next 12.00 alpha 允许用户之后通过点击某处将范围重置为 null;Firefox 12.0a1 和 Chrome 17 dev 则不允许。我们遵循 Gecko/WebKit,因为这样可以降低 getRangeAt(0) 抛出异常的可能性。

一旦一个选区与给定范围关联,它 必须继续与同一个范围关联,直到本 规范另有要求。

注

例如,如果 DOM 以某种方式发生更改,从而改变范围的 边界点,或者脚本修改了范围的边界点, 同一个范围对象必须继续与该 选区关联。但是,如果用户更改了选区,或者脚本调用 addRange(),则选区必须 与一个新的范围 对象关联,如本规范其他部分所要求的那样。

如果选区的范围不为 null 且处于 折叠状态,那么插入符 位置必须位于该 范围的边界点。当 选区 不处于 折叠状态时,本 规范不定义插入符 位置;用户代理在决定插入符位于选区的起点、位于 选区的终点还是其他位置时,应遵循平台约定。

每个选区都有一个方向:向前、 向后,或无方向。如果 用户通过先指示 范围的一个边界点,然后再指示另一个边界点来创建 选区(例如点击一个点并 拖动到另一个点),并且第一个指示的边界点位于第二个边界点 之后, 那么相应的 选区最初必须为向后。如果第一个 指示的边界点位于 第二个边界点之前,那么相应的选区最初必须为 向前。 否则,它必须为无方向。

当选区的范围被脚本改变时,例如 通过 selectNode(node), 选区的方向 必须保留。

每个选区还有一个锚点和一个 焦点。如果选区的范围为 null,则其 锚点和焦点都为 null。如果选区的 范围不为 null,并且其方向为向前, 则其锚点是 范围的起点,其 焦点是终点。否则,其焦点是 起点,其锚点是 终点。

注

选区的锚点和 焦点不一定需要位于 文档树中。 它们可以位于同一 文档的影子 树中。

每个文档、input 元素和textarea 元素 都有一个布尔值已调度 selectionchange 事件,其 初始值为 false。

3. Selection 接口

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

该属性必须返回 this 的锚点节点, 如果锚点为 null,或 锚点 不在文档树中,则返回 null。

anchorOffset

该属性必须返回 this 的锚点偏移量,如果 锚点 为 null,或锚点不在文档树中,则返回 0。

focusNode

该属性必须返回 this 的焦点节点, 如果焦点为 null,或焦点 不在文档树中,则返回 null。

focusOffset

该属性必须返回 this 的焦点偏移量,如果 焦点 为 null,或焦点不在文档树中,则返回 0。

isCollapsed

当且仅当 锚点和焦点相同(包括 两者均为 null)时,该属性必须返回 true。否则必须返回 false。

rangeCount

如果 this 为 空,或 焦点或锚点中的任一个不在 文档树中, 该属性必须返回 0,否则必须返回 1。

type

如果 this 为空,或 焦点或锚点中的任一个不在文档树中, 该属性必须返回 "None";如果 this 的范围处于 折叠状态,则返回 "Caret";否则返回 "Range"。

direction

如果 this 为空,或 此选区为无方向,该属性必须返回 "none"。如果此 选区的方向为向前,则返回 "forward";如果此 选区的方向为向后,则返回 "backward"。

getRangeAt() 方法

如果 index 不是 0,或者 this 为 空,或 焦点或锚点中的任一个不在 文档树中, 该方法必须抛出 IndexSizeError 异常。 否则,它必须返回对 this 的范围的引用(而不是 副本)。

注

因此,如果在此期间没有任何操作移除 this 的范围,则后续调用此方法会返回同一个范围 对象。特别是,如果选区不是空, getSelection().getRangeAt(0) === getSelection().getRangeAt(0) 的求值结果为 true。

addRange() 方法

该方法必须遵循以下步骤:

  1. 如果 range 的边界点的根 不是与 this 关联的文档, 则中止这些 步骤。
  2. 如果 rangeCount 不是 0,则中止这些 步骤。
  3. 通过强引用 (而不是创建副本)将 this 的范围设置为 range。
注

由于范围是 通过引用添加的,因此后续调用 getRangeAt(0) 会返回同一个对象,并且脚本在添加后对范围所做的任何更改都必须 反映在选区中,直到其他操作移除或 替换 this 的范围。特别是,运行以下代码后, 选区将包含 b 而不是 a:var r = document.createRange(); r.selectNode(a); getSelection().addRange(r); r.selectNode(b);

注

在第 2 步中,Chrome 58 和 Edge 25 不执行任何操作。Firefox 51 会创建 一个多范围选区。至少它们都会保留现有的 范围。

在第 3 步中,Chrome 58 和 Firefox 51 会存储引用,如 此处所述。Edge 25 会存储副本。如果范围被修改,Firefox 51 会更改其 选区。

removeRange() 方法

如果 this 的范围为 range,该方法必须通过解除其 范围的关联,使 this 变为空。 否则,它必须抛出 NotFoundError。

removeAllRanges() 方法

如果 this 具有关联的范围,该方法必须通过解除其 范围的关联,使 this 变为空。

empty() 方法

该方法必须是 removeAllRanges() 的别名,并且其行为 必须完全相同。

getComposedRanges() 方法
  1. 如果 this 为空,则返回一个空数组。
  2. 否则,令 startNode 为与 this 关联的范围的起始节点, 并令 startOffset 为该范围的起始偏移量。
  3. 当 startNode 是一个节点, startNode 的根是一个影子根,并且 startNode 的根不是 options["shadowRoots"] 中任何项的包含影子的 包含自身祖先时, 重复以下步骤:
    1. 将 startOffset 设置为 startNode 的根的宿主的索引。
    2. 将 startNode 设置为 startNode 的 根的 宿主的父节点。
  4. 令 endNode 为与 this 关联的范围的结束节点, 并令 endOffset 为该范围的 结束 偏移量。
  5. 当 endNode 是一个节点,endNode 的 根是一个影子 根,并且 endNode 的 根不是 options["shadowRoots"] 中任何项的 包含影子的 包含自身祖先时, 重复以下步骤:
    1. 将 endOffset 设置为 endNode 的根的宿主的索引加 1。
    2. 将 endNode 设置为 endNode 的 根的 宿主的父节点。
  6. 返回一个由新的 StaticRange 组成的数组,其中 起始 节点为 startNode,起始偏移量为 startOffset,结束节点为 endNode,并且结束偏移量为 endOffset。
collapse() 方法

该方法必须遵循以下步骤:

  1. 如果 node 为 null,此方法的行为必须与 removeAllRanges() 完全相同,并中止这些步骤。
  2. 如果 node 是一个DocumentType,则抛出 InvalidNodeTypeError 异常并中止这些步骤。
  3. 如果 offset 大于 node 的长度,该方法必须抛出 IndexSizeError 异常并 中止这些步骤。
  4. 如果与 this 关联的文档不是 node 的包含影子的 包含自身祖先,则中止 这些步骤。
  5. 否则,令 newRange 为一个新的范围。
  6. 将 newRange 的起点和 终点设置为 (node, offset)。
  7. 将 this 的范围设置为 newRange。
setPosition() 方法

该方法必须是 collapse() 的别名,并且其行为 必须完全相同。

collapseToStart() 方法

如果 this 为空,该方法必须抛出 InvalidStateError 异常。否则,它必须 创建一个新的范围,将其起点 和 终点均设置为 this 的范围的起点, 然后将 this 的范围设置为 新创建的 范围。

注

对于 collapseToStart/End,IE9 会改变现有范围,而 Firefox 9.0a2 和 Chrome 15 dev 会用一个新范围替换它。本规范 遵循多数实现,用一个新范围替换它,并保持旧的 Range 对象不变。

collapseToEnd() 方法

如果 this 为空,该方法必须抛出 InvalidStateError 异常。否则,它必须 创建一个新的范围,将其起点 和 终点均设置为 this 的范围的终点,然后 将 this 的范围设置为 新创建的范围。

extend() 方法

该方法必须遵循以下步骤:

  1. 如果与 this 关联的文档 不是 node 的包含影子的 包含自身祖先,则中止 这些步骤。
  2. 如果 this 为空,则抛出 InvalidStateError 异常并中止这些步骤。
  3. 令 oldAnchor 和 oldFocus 分别为 this 的锚点和焦点,并令 newFocus 为边界点 (node, offset)。
  4. 令 newRange 为一个新的范围。
  5. 如果 node 的根与 this 的范围的根不同,则将 newRange 的起点和终点设置 为 newFocus。
  6. 否则,如果 oldAnchor 位于 newFocus之前 或与其相等,则将 newRange 的起点设置为 oldAnchor, 然后 将其终点设置为 newFocus。
  7. 否则,将 newRange 的 起点设置为 newFocus,然后将其终点 设置为 oldAnchor。
  8. 将 this 的范围设置为 newRange。
  9. 如果 newFocus 位于 oldAnchor之前,则将 this 的方向设置为 向后。否则,将其设置为向前。
注

这是在 2011 年 1 月前后通过逆向工程得出的。IE 不支持它,因此 我依赖 Firefox(在 2000 年之前的某个时候实现了 extend()) 和 WebKit(于 2007 年实现了 extend())。我基本忽略了 Opera,因为 gsnedders 告诉我它的实现并不 兼容。Firefox 12.0a1 似乎会改变现有范围。IE9 不支持 extend(),而且无法判断 Chrome 17 dev 或 Opera Next 12.00 alpha 是改变还是替换范围,因为 getRangeAt() 无论如何都会返回一个副本。尽管如此,我在这里选择与 Gecko 不同的做法,以便与 collapse() 保持一致。

setBaseAndExtent() 方法

该方法必须遵循以下步骤:

  1. 如果 anchorOffset 大于 anchorNode 的长度,或者 focusOffset 大于 focusNode 的 长度, 则抛出 IndexSizeError 异常并中止 这些步骤。
  2. 如果与 this 关联的文档不是 anchorNode 或 focusNode 的包含影子的 包含自身祖先,则中止这些步骤。
  3. 令 anchor 为边界点 (anchorNode, anchorOffset),并令 focus 为边界点 (focusNode, focusOffset)。
  4. 令 newRange 为一个新的范围。
  5. 如果 anchor 位于 focus之前,则将 newRange 的 起点设置为 anchor,并将其终点设置为 focus。否则,分别将它们设置为 focus 和 anchor。
  6. 将 this 的范围设置为 newRange。
  7. 如果 focus 位于 anchor之前,则将 this 的方向设置为 向后。否则,将其设置为向前
selectAllChildren() 方法

该方法必须遵循以下步骤:

  1. 如果 node 是一个DocumentType,则抛出 InvalidNodeTypeError 异常并中止这些步骤。
  2. 如果 node 的根不是与 this 关联的文档, 则中止这些步骤。
  3. 令 newRange 为一个新的范围,并令 childCount 为 node 的子节点数量。
  4. 将 newRange 的起点设置为 (node, 0)。
  5. 将 newRange 的终点设置为 (node, childCount)。
  6. 将 this 的范围设置为 newRange。
  7. 将 this 的方向设置为 forwards。
注

主要基于 Firefox 9.0a2。它有一个我没有 复现的 bug,即如果将 Document 作为参数传入, 结束偏移量会变为 1,而不是其子节点 的数量。它还会抛出 RangeException 而不是 DOMException, 因为它的实现早于这两者的合并。

IE9 的行为类似,但存在一些异常情况。如果节点已分离或 display:none,它会抛出“Unspecified error.”,而且显然 在其他一些随机情况下也会如此。对于 已分离的注释(仅此一种情况!),它会抛出“Invalid argument.”。最后,如果向其传入注释,它 似乎会选择整个注释,这与文本节点的行为不同。

Chrome 16 dev 的行为与其 Selection 实现所预期的一样。它拒绝选择任何不可见的内容, 因此几乎总是错误的。Opera 11.50 像往常一样,在我的所有 测试中都不执行任何操作。

新范围会替换任何现有范围,而不会改变它。这 与 IE9 和 Firefox 12.0a1 一致。(Chrome 17 dev 和 Opera Next 12.00 alpha 无法测试,因为 getRangeAt() 无论如何都会返回一个副本。)

modify() 方法

该方法必须遵循以下步骤:

  1. 如果 alter 与 "extend" 或 "move" 不ASCII 大小写不敏感 匹配,则中止这些步骤。
  2. 如果 direction 与 "forward"、"backward"、"left" 或 "right" 不ASCII 大小写不敏感 匹配,则中止这些 步骤。
  3. 如果 granularity 与 "character"、"word"、"sentence"、"line"、"paragraph"、 "lineboundary"、"sentenceboundary"、"paragraphboundary"、 "documentboundary" 中的任一项不ASCII 大小写不敏感 匹配,则中止这些步骤。
  4. 如果 this 选区为空,则中止这些步骤。
  5. 令 effectiveDirection 为向后。
  6. 如果 direction 与 "forward" ASCII 大小写不敏感 匹配,则将 effectiveDirection 设置为 向前。
  7. 如果 direction 与 "right" ASCII 大小写不敏感 匹配,并且 this 选区的焦点处的解析文本方向 为ltr,则将 effectiveDirection 设置为向前。
  8. 如果 direction 与 "left" ASCII 大小写不敏感 匹配,并且 this 选区的焦点处的解析文本方向 为rtl,则将 effectiveDirection 设置为向前。
  9. 将 this 选区的方向设置为 effectiveDirection。
  10. 如果 alter 与 "extend" ASCII 大小写不敏感 匹配,则将 this 选区的焦点设置为 就像用户请求按 granularity 扩展选区时所在的位置。
  11. 否则,将 this 选区的焦点和 锚点设置为就像用户请求按 granularity 移动选区时所在的位置。

在一个边界点处的解析文本方向: 如果该位置字符的嵌入 方向([UAX9] BD3)为 L,则为ltr;如果嵌入 方向为 R,则为rtl。

注

在双向文本边界处——即相邻字符具有不同 嵌入方向的位置——用户代理可以使用其他上下文 (例如基于光标 移动方向的插入符亲和性)来确定使用哪个字符的嵌入方向。

注

我们需要更精确地定义按每种粒度扩展或移动 选区的含义。

deleteFromDocument() 方法

如果 this 不是空, 并且焦点 和锚点都位于文档树中,则该方法必须在 this 的 范围上调用 deleteContents()。 否则,该 方法必须不执行任何操作。

注

这是唯一一个实际改变范围而不是 替换它的方法。这与 IE9 和 Firefox 12.0a1 一致。(Chrome 17 dev 和 Opera Next 12.00 alpha 无法测试,因为 getRangeAt() 无论如何都会返回副本。)

containsNode() 方法

如果 this 为 空,或者 node 的根不是与 this 关联的 文档,则该方法必须返回 false。

否则,如果 allowPartialContainment 为 false,则当且仅当其范围的起点位于 node 中第一个边界 点之前或在视觉上与其等价,并且其范围的终点 位于 node 中最后一个边界点之后或在视觉上 与其等价时,该方法才必须返回 true。

如果 allowPartialContainment 为 true,则 当且仅当其范围的起点 位于 node 中最后一个边界点之前或在视觉上 与其等价,并且其范围的终点 位于 node 中第一个 边界点之后或在视觉上与其等价时,该方法才必须返回 true。

stringifier

如果存在与 this 关联的范围, 字符串化必须返回由已渲染文本连接而成的 字符串。

如果选区位于 textarea 或 input 元素内,则必须返回其值中被选中的子字符串。

注意

另见来自 Gecko 的 nsISelection.idl。本规范尚未包含那里的所有内容,特别是 selectionLanguageChange() 和 containsNode() 尚缺失。它们缺失的原因是我无法弄清如何用 Range 来定义它们。

注意

最初,Selection 接口是一个 Netscape 的特性。其原始实现被带入到 Gecko(Firefox),随后该特性被其他浏览器引擎独立实现。Netscape 的实现始终允许在单个选择中存在多个范围,例如用户可以选择表格的一列。然而,多范围选择证明是一个让 Web 开发者不易察觉并且即使是 Gecko 的开发者也很少正确处理的不愉快的边界情况。其他浏览器引擎从未实现该特性,并以各种不兼容的方式将选择限制为单个范围。

本规范遵循非 Gecko 引擎,将选择限制为最多一个范围,但该 API 最初仍为支持任意数量范围的选择而设计。这解释了像 removeRange() 与 removeAllRanges() 并存以及 getRangeAt() 方法接受一个必须始终为零的整数参数等奇怪之处。

所有 Selection 接口的成员都是以该对象所表示的 range 对象(如果有的话)上的操作来定义的。这些操作可能会引发异常,如在 Range 接口的定义中所述;因此,这也可能导致 Selection 接口的成员抛出异常,除上文明确指出的情况外。

4. 对其他接口的扩展

本规范扩展了若干接口以提供到本规范中定义的接口的入口点。

4.1 对 Document 接口的扩展

Document 接口在 [HTML] 中定义。

WebIDLpartial interface Document {
  Selection? getSelection();
};
getSelection() method

该方法必须返回与 此对象 关联的 选择,如果 此对象 拥有关联的 浏览上下文;否则必须返回 null。

4.2 对 Window 接口的扩展

Window 接口在 [HTML] 中定义。

WebIDLpartial interface Window {
  Selection? getSelection();
};
getSelection() method

该方法必须调用并返回 getSelection() 在 此对象 的 Window 的 document 属性上的结果。

4.3 对 GlobalEventHandlers 接口的扩展

GlobalEventHandlers 接口在 [HTML] 中定义。

WebIDLpartial interface mixin GlobalEventHandlers {
  attribute EventHandler onselectstart;
  attribute EventHandler onselectionchange;
};
onselectstart

该属性必须是一个针对 selectstart 事件的 事件处理器 IDL 属性,该事件由所有 HTML 元素、Document 对象和 Window 对象支持。

onselectionchange

该属性必须是一个针对 selectionchange 事件的 事件处理器 IDL 属性,该事件由所有 HTML 元素、Document 对象和 Window 对象支持。

5. 响应 DOM 变更

当用户代理在 CharacterData 上替换数据或截取子数据时,用户代理必须像操作活动范围一样,更新该CharacterData的节点文档的选择关联的范围。

当用户代理要拆分 Text 节点时,用户代理必须像操作活动范围一样,更新该Text的节点文档的选择关联的范围。

当用户代理执行 normalize() 方法步骤时,用户代理必须像操作活动范围一样,更新 此的节点文档的选择关联的范围。

当用户代理要移除或插入一个节点时,用户代理必须像操作活动范围一样,更新该节点的节点文档的选择关联的范围。

6. 用户交互

用户代理应允许用户更改与选择 关联的活动文档。 如果用户对选择进行了任何修改,用户代理必须创建一个具有合适起始和结束的新的范围,并将选择与这个新范围关联(而不是修改现有的范围),并根据以下规则设置和更新选择的方向:如果起始小于或等于结束则设为正向;如果结束小于起始则设为反向;如果由于平台惯例无法判断起始和结束的顺序则设为无方向。

对于任何用户操作(如点击非可编辑区域),如果选择原本非空,用户代理不得将其设为空。

注意

见bug 15470。IE9 和 Opera Next 12.00 alpha 允许用户点击后将范围重置为 null;Firefox 12.0a1 和 Chrome 17 dev 则不会。我遵循 Gecko/WebKit,这样 getRangeAt(0) 抛出异常的机会更小。

6.1 selectstart 事件

当用户代理准备在响应用户操作时将新的 newRange 关联到 选择上时,如果之前的 选择是空或原关联范围是折叠状态,则必须在更改选择前,于与 newRange 的边界点相关的节点上,触发一个冒泡且可取消的名为selectstart的事件。

如果该事件被取消,则用户代理不得更改选择。

当用户代理将选择设为空empty时,不得触发事件。

6.2 selectionchange 事件

当选择与其范围解除关联、关联新的范围,或关联的范围的边界点被用户或内容脚本修改时,用户代理必须在文档上调度 selectionchange 事件。

当 input 或 textarea 元素提供文本选择,且其选择(范围或方向)发生变化时,用户代理必须在该元素上调度 selectionchange 事件。

6.2.1 调度 selectionchange 事件

在 节点 target 上调度 selectionchange 事件,按以下步骤操作:

  1. 如果 target 的 has scheduled selectionchange event 为 true,则中止这些步骤。
  2. 将 target 的 已调度 selectionchange 事件设为 true。
  3. 在用户交互任务源上排入一个任务 于 target 上触发 selectionchange 事件。

6.2.2 触发 selectionchange 事件

在节点 target 上触发 selectionchange 事件,按以下步骤操作:

  1. 将 target 的 has scheduled selectionchange event 设为 false。
  2. 如果 target 是元素,则在 target 上触发一个名字为 selectionchange、可冒泡但不可取消的事件。
  3. 否则如果 target 是文档,则在 target 上触发一个名字为 selectionchange、不可冒泡且不可取消的事件。

7. 一致性

本规范中标记为非规范性(non-normative)的部分,以及所有作者指南、图示、示例和说明都是非规范性的。本规范中其余内容均为规范性内容。

本规范定义了适用于单一产品的符合性标准:实现本规范所含接口的用户代理。

8. 安全性与隐私注意事项

目前该标准未发现已知的安全性考量。

为减轻暴露用户辅助技术使用情况的潜在隐私风险,例如,用户代理可选择在用户修改文档选择时,模拟通常与selectstart或selectionchange事件有关的鼠标和键盘事件。

A. 致谢

特别感谢

B. 参考文献

B.1 规范性引用

[css-writing-modes-4]
CSS 书写模式第 4 级。 Elika Etemad; Koji Ishii。W3C。2019 年 7 月 30 日。W3C 候选推荐标准。URL:https://www.w3.org/TR/css-writing-modes-4/
[dom]
DOM 标准。Anne van Kesteren。WHATWG。 现行标准。URL:https://dom.spec.whatwg.org/
[HTML]
HTML 标准。Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters。WHATWG。现行 标准。URL:https://html.spec.whatwg.org/multipage/
[infra]
Infra 标准。Anne van Kesteren; Domenic Denicola。WHATWG。现行标准。URL:https://infra.spec.whatwg.org/
[UAX9]
Unicode 双向 算法。Manish Goregaokar मनीष गोरेगांवकर; Robin Leroy。Unicode Consortium。2025 年 8 月 13 日。Unicode 标准附录 #9。URL:https://www.unicode.org/reports/tr9/tr9-51.html
[url]
URL 标准。Anne van Kesteren。WHATWG。 现行标准。URL:https://url.spec.whatwg.org/
[WEBIDL]
Web IDL 标准。Edgar Chen; Timothy Gu。 WHATWG。现行标准。URL:https://webidl.spec.whatwg.org/