选择 API

W3C 工作草案

关于此文档的更多详细信息
本版本:
https://www.w3.org/TR/2025/WD-selection-api-20250105/
最新发布版本:
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 technical reports index 的 https://www.w3.org/TR/ 找到。

该工作仍在进行中。

本文件由 Web Editing Working Group 作为工作草案发布,使用 Recommendation track

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

本文件为草案,可能随时被其它文件更新、替换或废弃。不应将本文件作为除正在进行中的工作以外的正式引用来源。

本文件由在 W3C Patent Policy 下运作的小组编写。 W3C 保持一份 与该小组交付物相关的任何专利披露的公开清单; 该页面还包含披露专利的说明。若个人实际知悉其认为包含 必要权利要求 的专利,则必须按照 W3C 专利政策第6节 的规定披露相关信息。

本文件受 2023年11月03日 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 bugWebKit bug

这个选择必须被文档的所有内容共享(但不包括嵌套的文档),包括文档内的任意编辑宿主

每个选择可与单个范围关联。当范围没有与选择关联时, 选择为。选择最初必须为

注意

文档选择是与该文档关联的单例对象,因此在调用 Document.open() 时会被新对象替换。参见 bug 15470。 IE9 和 Opera Next 12.00 alpha 允许用户通过点击操作后将 range 重置为 null;Firefox 12.0a1 和 Chrome 17 dev 则不允许。我们遵循 Gecko/WebKit 的行为,因为这样 getRangeAt(0) 抛异常的概率更低。

一旦选择与指定范围关联,除非本规范要求,否则必须持续与该 范围关联。

注意

例如,如果 DOM 发生变化导致范围的边界点发生改变,或者脚本修改了范围的边界点,则仍必须使用同一个范围对象与选择关联。但如果用户更改选择或者脚本调用addRange(),则该选择必须与新范围对象关联,其他地方有要求。

如果选择范围不为 null 且已折叠,则插入符号的位置必须在该边界点。当选择折叠时,本规范未定义插入符号位置;用户代理应遵循平台惯例决定插入符号是在选择的起始、末尾或其它位置。

每个选择有一个方向正向反向无方向。当用户首先按下一个边界点,再按下另一个(如,点击某一点再拖至另一点)时,如果第一个边界点在第二个之后,则该选择初始为反向。如果第一个边界点在第二个之前,则初始为正向。 否则应为无方向

选择范围被脚本修改(例如调用selectNode(node)), 方向必须被保留。

每个选择还具有锚点焦点。如果选择范围为 null,其锚点焦点都为 null。 若范围非 null 且方向正向锚点为范围的起点, 焦点为终点。否则 焦点为起点, 锚点为终点。

注意

锚点焦点不必在文档树内,可以在同一影子树中。

每个文档input 元素 和 textarea 元素 有一个布尔值属性has scheduled selectionchange event,其初始为 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

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

anchorOffset

该属性必须返回此对象的 锚点偏移量;如果 锚点null 或者 锚点不在 文档树中,则返回 0

focusNode

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

focusOffset

该属性必须返回此对象的 焦点偏移量;如果 焦点null 或者 焦点不在 文档树中,则返回 0

isCollapsed

只有当 anchorfocus 相同时(包括两者均为 null 的情况)该属性才应返回 true。否则应返回 false。

rangeCount

如果 此对象,或 focusanchor 任何一个不在 文档树 中,则该属性必须返回 0,否则返回 1

type

如果 此对象,或 focusanchor 任一不在 文档树 中,则该属性必须返回 "None";如果此对象的 range折叠,则返回 "Caret";否则返回 "Range"

direction

如果 此对象 或者该选择为 无方向,则该属性必须返回 "none"。如果该选择的方向为 正向,返回 "forward";如果方向为 反向,返回 "backward"

getRangeAt() method

如果 index 不是 0,或者 此对象,或 focusanchor 任何一个不在 文档树 中,则该方法必须抛出 IndexSizeError 异常。否则,必须返回对此对象的 范围 的引用(不是副本)。

注意

因此,如果在此期间没有移除此对象的范围,随后对该方法的调用将返回相同的 范围 对象。特别是,当选择非空时,getSelection().getRangeAt(0) === getSelection().getRangeAt(0) 的求值应为 true

addRange() method

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

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

由于是按引用添加 range,随后对 getRangeAt(0) 的调用会返回相同的对象,并且脚本在添加之后对该 range 所做的任何更改必须反映在选择中,直到该范围被移除或替换为止。特别地,运行如下代码后:var r = document.createRange(); r.selectNode(a); getSelection().addRange(r); r.selectNode(b);选择 将包含 b 而不是 a

注意

在步骤 2,Chrome 58 和 Edge 25 什么也不做。Firefox 51 会给出多范围选择。至少它们保留了现有的 range

在步骤 3,Chrome 58 和 Firefox 51 如此存储引用。如上所述。Edge 25 存储副本。Firefox 51 在 range 被修改时会改变其选择。

removeRange() method

该方法必须通过解除关联其 范围 来使 此对象 变为 ,前提是此对象的范围正是 range。否则,必须抛出 NotFoundError

removeAllRanges() method

该方法必须在此对象有关联的 范围 时,通过解除关联该范围使 此对象 变为

empty() method

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

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

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

  1. 如果 node 为 null,则此方法必须表现得与 removeAllRanges() 完全相同,并中止这些步骤。
  2. 如果 node 是一个 DocumentType,则抛出 InvalidNodeTypeError 异常并中止这些步骤。
  3. 如果 offset 大于 node长度,则抛出 IndexSizeError 异常并中止这些步骤。
  4. 如果与 此对象 关联的 文档 不是 影子包含性祖先(shadow-including inclusive ancestor) 的 node,则中止这些步骤。
  5. 否则,令 newRange 为一个新的 范围
  6. newRange起始结束 设置为 (node, offset)。
  7. 此对象范围 设置为 newRange
setPosition() method

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

collapseToStart() method

如果 InvalidStateError 异常如果 此对象,则应抛出该异常。否则,必须创建一个新的 范围,将其 起始结束 都设置为此对象的范围的起始位置,然后将此对象的范围设置为新创建的范围。

注意

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

collapseToEnd() method

如果 InvalidStateError 异常如果 此对象,则应抛出该异常。否则,必须创建一个新的 范围,将其 起始结束 都设置为此对象的范围的结束位置,然后将此对象的范围设置为新创建的范围。

extend() method

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

  1. 如果与 此对象 关联的 文档 不是 影子包含性祖先node,则中止这些步骤。
  2. 如果 此对象,则抛出 InvalidStateError 并中止这些步骤。
  3. oldAnchoroldFocus 分别为此对象的 锚点焦点,并令 newFocus 为边界点 (node, offset)。
  4. newRange 为一个新的 范围
  5. 如果 node 与此对象的范围的根不同,则将 newRange起始结束 都设置为 newFocus
  6. 否则,如果 oldAnchornewFocus 之前或等于 newFocus,则将 newRange起始 设置为 oldAnchor,然后将其 结束 设置为 newFocus
  7. 否则,将 newRange起始 设置为 newFocus,然后将其 结束 设置为 oldAnchor
  8. 将此对象的 范围 设置为 newRange
  9. 如果 newFocusoldAnchor 之前,则将此对象的 方向 设置为 反向;否则设置为 正向
注意

约在 2011 年 1 月进行的逆向工程。IE 不支持该方法,因此我依赖 Firefox(在 2000 年之前实现了 extend())和 WebKit(2007 年实现 extend())。我基本上忽略 Opera,因为其实现据说不兼容。Firefox 12.0a1 似乎会修改现有范围。IE9 不支持 extend(),而 Chrome 17 dev 或 Opera Next 12.00 alpha 是否修改或替换无法判断,因为 getRangeAt() 无论如何都会返回副本。尽管如此,为与 collapse() 保持一致,我在这里不采用 Gecko 的行为。

setBaseAndExtent() method

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

  1. 如果 anchorOffset 大于 anchorNode长度,或 focusOffset 大于 focusNode长度,则抛出 IndexSizeError 异常并中止这些步骤。
  2. 如果与 此对象 关联的 文档 不是 影子包含性祖先anchorNodefocusNode,则中止这些步骤。
  3. anchor 为边界点 (anchorNode, anchorOffset),令 focus 为边界点 (focusNode, focusOffset)。
  4. newRange 为一个新的 范围
  5. 如果 anchorfocus 之前,则将 newRange起始 设置为 anchor,并将其 结束 设置为 focus;否则,将起始和结束分别设置为 focusanchor
  6. 将此对象的 范围 设置为 newRange
  7. 如果 focusanchor 之前,则将此对象的 方向 设置为 反向;否则设置为 正向
selectAllChildren() method

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

  1. 如果 node 是一个 DocumentType,则抛出 InvalidNodeTypeError 并中止这些步骤。
  2. 如果 node 不是与 此对象 关联的 文档,则中止这些步骤。
  3. newRange 为一个新的 范围,并令 childCountnode 的子节点数。
  4. newRange起始 设置为 (node, 0)。
  5. newRange结束 设置为 (node, childCount)。
  6. 将此对象的 范围 设置为 newRange
  7. 将此对象的 方向 设置为 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() method

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

  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. 如果 此对象选择 为空,则中止这些步骤。
  5. effectiveDirection反向
  6. 如果 direction 与 "forward" 在 ASCII 不区分大小写意义下匹配,则将 effectiveDirection 设置为 正向
  7. 如果 direction 与 "right" 在 ASCII 不区分大小写意义下匹配,且此对象的 inline base direction(内联基方向)为 ltr,则将 effectiveDirection 设置为 正向
  8. 如果 direction 与 "left" 在 ASCII 不区分大小写意义下匹配,且此对象的选择的内联基方向为 rtl,则将 effectiveDirection 设置为 正向
  9. 将此对象的 选择方向 设置为 effectiveDirection
  10. 如果 alter 与 "extend" 在 ASCII 不区分大小写意义下匹配,则将此对象的 选择焦点 设置为用户请求按 granularity 扩展选择时应到达的位置。
  11. 否则,将此对象的 选择焦点锚点 设置为用户请求按 granularity 移动选择时应到达的位置。
注意

我们需要更精确定义按每种粒度扩展或移动选择意味着什么。

deleteFromDocument() method

如果此对象非 focusanchor 均在 文档树 中,则该方法必须在此对象的 范围 上调用 deleteContents()。否则该方法不得执行任何操作。

注意

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

containsNode() method

如果 此对象,或 node 不是与 此对象 关联的文档,则该方法必须返回 false

否则,如果 allowPartialContainmentfalse,当且仅当其 范围起始node 中的第一个边界点之前或视觉等价且其范围的 结束node 中的最后一个边界点之后或视觉等价时,该方法返回 true

如果 allowPartialContainmenttrue,当且仅当其范围的 起始node 中的最后一个边界点之前或视觉等价且其范围的 结束node 中的第一个边界点之后或视觉等价时,该方法返回 true

stringifier

字符串化必须返回一个字符串,该字符串是与此对象关联的 范围 的呈现文本的连接结果。

如果选择位于 textareainput 元素内,则必须返回其 value 中被选中的子字符串。

注意

另见来自 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()此对象Windowdocument 属性上的结果。

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 事件

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

6.2.1 调度 selectionchange 事件

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

  1. 如果 targethas scheduled selectionchange event 为 true,则中止这些步骤。
  2. 用户交互任务源排入一个任务target触发 selectionchange 事件

6.2.2 触发 selectionchange 事件

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

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

7. 一致性

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

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

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

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

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

A. 致谢

特别感谢

B. 参考文献

B.1 规范性引用

[css-writing-modes-4]
CSS Writing Modes Level 4。 Elika Etemad;Koji Ishii。W3C。2019年7月30日。W3C 候选推荐标准。URL:https://www.w3.org/TR/css-writing-modes-4/
[dom]
DOM Standard。Anne van Kesteren。WHATWG。终身标准。URL:https://dom.spec.whatwg.org/
[HTML]
HTML Standard。Anne van Kesteren;Domenic Denicola;Dominic Farolino;Ian Hickson;Philip Jägenstedt;Simon Pieters。WHATWG。终身标准。URL:https://html.spec.whatwg.org/multipage/
[infra]
Infra Standard。Anne van Kesteren;Domenic Denicola。WHATWG。终身标准。URL:https://infra.spec.whatwg.org/
[url]
URL Standard。Anne van Kesteren。WHATWG。终身标准。URL:https://url.spec.whatwg.org/
[WEBIDL]
Web IDL Standard。Edgar Chen;Timothy Gu。WHATWG。终身标准。URL:https://webidl.spec.whatwg.org/