1. 6 用户交互
    1. 6.1 hidden 属性
    2. 6.2 页面可见性
      1. 6.2.1 VisibilityStateEntry 接口
    3. 6.3 无效子树
      1. 6.3.1 模态对话框和无效子树
      2. 6.3.2 inert 属性
    4. 6.4 跟踪用户激活
      1. 6.4.1 UserActivation 接口
    5. 6.5 元素的激活行为
      1. 6.5.1 ToggleEvent 接口
    6. 6.6 焦点
      1. 6.6.1 简介
      2. 6.6.2 数据模型
      3. 6.6.3 tabindex 属性
      4. 6.6.4 焦点管理 API
      5. 6.6.5 autofocus 属性
    7. 6.7 分配键盘快捷键
      1. 6.7.1 简介
      2. 6.7.2 accesskey 属性
    8. 6.8 编辑
      1. 6.8.1 使文档区域可编辑:contenteditable 内容属性
      2. 6.8.2 使整个文档可编辑:designMode 获取器和设置器
      3. 6.8.3 页面内编辑器的最佳实践
      4. 6.8.4 拼写和语法检查
      5. 6.8.5 写作建议
      6. 6.8.6 自动大写
      7. 6.8.7 自动更正
      8. 6.8.8 输入模式:inputmode 属性
      9. 6.8.9 输入模式:enterkeyhint 属性
    9. 6.9 页面内查找
      1. 6.9.1 简介
      2. 6.9.2detailshidden=until-found 的交互
      3. 6.9.3 与选择的交互
    10. 6.10 关闭请求和关闭观察者
      1. 6.10.1 关闭请求
      2. 6.10.2 CloseWatcher 接口

6 用户交互

6.1 hidden 属性

Global_attributes/hidden

仅在一个引擎中受支持。

FirefoxSafariChrome102+
OperaEdge102+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

Global_attributes/hidden

在所有当前引擎中受支持。

Firefox4+Safari5.1+Chrome10+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer11
Firefox Android?Safari iOS?Chrome Android?WebView Android4+Samsung Internet?Opera Android?

所有 HTML 元素 都可以设置 hidden 内容属性。hidden 属性是一个 枚举属性,具有以下关键字和状态

关键字状态简要描述
hidden hidden 将不会被渲染。
(空字符串)
until-found 隐藏直到找到 将不会被渲染,但内部内容将可供 页面内查找片段导航 访问。

该属性的 缺省值不隐藏 状态,其 无效值hidden 状态。

当元素具有 hidden 属性处于 hidden 状态时,它表示该元素尚未或不再直接与页面的当前状态相关,或者它用于声明要由页面的其他部分重用的内容,而不是由用户直接访问。用户代理不应渲染处于 hidden 状态的元素。此要求可以通过样式层间接实现。例如,Web 浏览器可以使用 渲染部分中建议的规则 来实现这些要求。

当元素具有 hidden 属性处于 hidden until found 状态时,它表示该元素像 hidden 状态一样隐藏,但元素内部的内容将可供 页面内查找片段导航 访问。当这些功能尝试滚动到元素子树中的目标时,用户代理将删除 hidden 属性以在滚动到目标之前显示内容。除了删除 hidden 属性之外,还会在元素上触发名为 beforematch 的事件,然后再删除 hidden 属性。

hidden 属性处于 hidden until found 状态时,Web 浏览器将使用“content-visibility: hidden”而不是“display: none”,如 渲染部分 中所述。

由于此属性通常使用 CSS 实现,因此也可以使用 CSS 覆盖它。例如,应用“display: block”于所有元素的规则将取消 hidden 状态的效果。因此,作者在编写样式表时必须注意,确保该属性仍然按预期进行样式设置。此外,不支持 hidden until found 状态的旧版用户代理将使用“display: none”而不是“content-visibility: hidden”,因此建议作者确保他们的样式表不会更改 hidden until found 元素的“display”或“content-visibility”属性。

由于具有 hidden 属性处于 hidden until found 状态的元素使用“content-visibility: hidden”而不是“display: none”,因此 hidden until found 状态有两个与 hidden 状态不同的注意事项

  1. 该元素需要受到 布局包含 的影响,才能通过页面内查找显示出来。这意味着,如果处于 hidden until found 状态的元素的“display”值为“none”、“contents”或“inline”,则该元素将不会通过页面内查找显示出来。

  2. 当元素处于 hidden until found 状态时,它仍然会有一个 生成的框,这意味着边框、边距和填充将仍然在元素周围渲染。

在以下骨架示例中,该属性用于隐藏 Web 游戏的主屏幕,直到用户登录

  <h1>The Example Game</h1>
  <section id="login">
   <h2>Login</h2>
   <form>
    ...
    <!-- calls login() once the user's credentials have been checked -->
   </form>
   <script>
    function login() {
      // switch screens
      document.getElementById('login').hidden = true;
      document.getElementById('game').hidden = false;
    }
   </script>
  </section>
  <section id="game" hidden>
   ...
  </section>

hidden 属性不得用于隐藏本来可以在其他演示中显示的内容。例如,使用 hidden 来隐藏选项卡式对话框中的面板是不正确的,因为选项卡式接口仅仅是一种溢出演示 — 人们同样也可以在一个包含滚动条的大页面中显示所有窗体控件。同样,使用此属性仅仅从一个演示中隐藏内容也是不正确的 — 如果某物被标记为 hidden,那么它将从所有演示中隐藏,包括例如屏幕阅读器。

本身不处于 hidden 状态的元素和脚本不得 超链接 到处于 hidden 状态的元素。本身不处于 hidden 状态的 labeloutput 元素的 for 属性也同样不得引用处于 hidden 状态的元素。在这两种情况下,此类引用都会导致用户混淆。

但是,元素和脚本可以在其他上下文中引用处于 hidden 状态的元素。

例如,使用 href 属性链接到用 hidden 属性标记的部分是不正确的。如果内容不适用或不相关,那么就没有理由链接到它。

但是,可以使用 ARIA aria-describedby 属性来引用本身处于 hidden 状态的描述。虽然隐藏描述意味着它们本身没有用,但可以这样编写它们,以便在从它们所描述的元素中被引用时的特定上下文中是有用的。

同样,具有 hidden 属性的 canvas 元素可以被脚本化的图形引擎用作屏幕外缓冲区,窗体控件可以使用其 form 属性引用隐藏的 form 元素。

处于 hidden 属性隐藏的部分中的元素仍然处于活动状态,例如,此类部分中的脚本和窗体控件仍然分别执行和提交。只有它们对用户的显示方式发生了变化。

6.2 页面可见性

一个 可遍历导航系统可见性状态,包括其创建时的初始值,由用户代理确定。它表示例如浏览器窗口是否最小化、浏览器标签页当前是否处于后台、或任务切换器等系统元素是否遮挡页面。

当用户代理确定 可遍历导航 traversable系统可见性状态 已更改为 newState 时,它必须运行以下步骤

  1. navigablestraversable活动文档包含的子代导航

  2. 对于每个 navigablesnavigable 以什么顺序?

    1. documentnavigable活动文档

    2. 在用户交互任务源上排队一个全局任务,给定 document相关全局对象,以 更新 document 的可见性状态,并使用 newState

一个 Document 具有一个 可见性状态,它可以是 "hidden" 或 "visible",最初设置为 "hidden"。

Document/visibilityState

在所有当前引擎中受支持。

Firefox18+Safari7+Chrome33+
Opera20+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS?Chrome Android?WebView Android4.4.3+Samsung Internet?Opera Android20+

The visibilityState getter steps are to return this's visibility state.

Document/hidden

在所有当前引擎中受支持。

Firefox18+Safari7+Chrome33+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS?Chrome Android?WebView Android4.4.3+Samsung Internet?Opera Android12.1+

The hidden getter steps are to return true if this's visibility state is "hidden", otherwise false.

To update the visibility state of Document document to visibilityState

  1. If document's visibility state equals visibilityState, then return.

  2. Set document's visibility state to visibilityState.

  3. Queue a new VisibilityStateEntry whose visibility state is visibilityState and whose timestamp is the current high resolution time given document's relevant global object.

  4. Run the screen orientation change steps with document. [SCREENORIENTATION]

  5. Run the view transition page visibility change steps with document.

  6. Run any page visibility change steps which may be defined in other specifications, with visibility state and document.

    It would be better if specification authors sent a pull request to add calls from here into their specifications directly, instead of using the page visibility change steps hook, to ensure well-defined cross-specification call order. As of the time of this writing the following specifications are known to have page visibility change steps, which will be run in an unspecified order: Device Posture API and Web NFC. [DEVICEPOSTURE] [WEBNFC]

  7. Fire an event named visibilitychange at document, with its bubbles attribute initialized to true.

6.2.1 The VisibilityStateEntry interface

VisibilityStateEntry

仅在一个引擎中受支持。

FirefoxNoSafariNoChrome115+
Opera?Edge115+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

The VisibilityStateEntry interface exposes visibility changes to the document, from the moment the document becomes active.

For example, this allows JavaScript code in the page to examine correlation between visibility changes and paint timing
function wasHiddenBeforeFirstContentfulPaint() {
    const fcpEntry = performance.getEntriesByName("first-contentful-paint")[0];
    const visibilityStateEntries = performance.getEntriesByType("visibility-state");
    return visibilityStateEntries.some(e =>
                                            e.startTime < fcpEntry.startTime &&
                                            e.name === "hidden");
}

Since hiding a page can cause throttling of rendering and other user-agent operations, it is common to use visibility changes as an indication that such throttling has occurred. However, other things could also cause throttling in different browsers, such as long periods of inactivity.

The VisibilityStateEntry has an associated DOMHighResTimeStamp timestamp.

The VisibilityStateEntry has an associated "visible" or "hidden" visibility state.

The name getter steps are to return this's visibility state.

The entryType getter steps are to return "visibility-state".

The startTime getter steps are to return this's timestamp.

The duration getter steps are to return zero.

6.3 惰性子树

另请参阅 inert,以了解同名属性的解释。

一个节点(特别是元素和文本节点)可以是 惰性。当一个节点是 惰性

惰性节点通常无法获得焦点,并且用户代理不会将惰性节点公开给可访问性 API 或辅助技术。作为 命令 的惰性节点将对用户变得不可用,如上所述。

然而,用户代理可能允许用户覆盖对 页面查找 和文本选择的限制。

默认情况下,节点不是 惰性

一个 Document document被模态对话框 subject 阻止的,如果 subjectdocument顶层 中最顶层的 dialog 元素。当 document 被阻止时,每个连接到 document 的节点(除了 subject 元素及其 扁平树 子代外)必须变为 惰性

subject 可以通过 inert 属性进一步变为 惰性,但前提是必须在 subject 本身指定(即 subject 逃避祖先的惰性);subject扁平树 子代可以以类似的方式变为 惰性

The dialog 元素的 showModal() 方法会通过 添加 dialog 元素到其 节点文档顶层 来触发此机制。

6.3.2 The inert attribute

Global_attributes/inert

在所有当前引擎中受支持。

Firefox112+Safari15.5+Chrome102+
Opera?Edge102+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

The inert attribute is a boolean attribute that indicates, by its presence, that the element and all its flat tree descendants which don't otherwise escape inertness (such as modal dialogs) are to be made inert by the user agent.

一个惰性子树不应该包含任何对理解或使用非惰性状态页面方面至关重要的内容或控件。惰性子树中的内容将不会被所有用户感知或交互。作者不应该将元素指定为惰性,除非它们所代表的内容也以某种方式在视觉上被遮挡。在大多数情况下,作者不应该在单个表单控件上指定 inert 属性。在这些情况下,disabled 属性可能更合适。

以下示例显示了如何将部分加载的内容标记为惰性,该内容在视觉上被“加载”消息遮挡。

<section aria-labelledby=s1>
  <h3 id=s1>Population by City</h3>
  <div class=container>
    <div class=loading><p>Loading...</p></div>
    <div inert>
      <form>
        <fieldset>
          <legend>Date range</legend>
          <div>
            <label for=start>Start</label>
            <input type=date id=start>
          </div>
          <div>
            <label for=end>End</label>
            <input type=date id=end>
          </div>
          <div>
            <button>Apply</button>
          </div>
        </fieldset>
      </form>
      <table>
        <caption>From 20-- to 20--</caption>
        <thead>
          <tr>
            <th>City</th>
            <th>State</th>
            <th>20-- Population</th>
            <th>20-- Population</th>
            <th>Percentage change</th>
          </tr>
        </thead>
        <tbody>
          <!-- ... -->
        </tbody>
      </table>
    </div>
  </div>
</section>
Screenshot of Population by City content with an overlaid loading message which visually obscures the form controls and data table which have not fully rendered, and thus are in the inert state.

“加载”覆盖层遮挡了惰性内容,使其在视觉上明显表明惰性内容目前不可访问。请注意,标题和“加载”文本不是具有 inert 属性的元素的后代。这将确保此文本对所有用户都可访问,而惰性内容则无法被任何人交互。

默认情况下,没有元素或其子树处于惰性状态的持久视觉指示。这种内容的适当视觉样式通常取决于上下文。例如,惰性屏幕外导航面板不需要默认样式,因为其屏幕外位置在视觉上遮挡了内容。类似地,模态 dialog 元素的背景将作为视觉上遮挡网页惰性内容的方式,而不是专门设置惰性内容的样式。

但是,对于许多其他情况,强烈建议作者清楚地标记其文档的哪些部分是活动的,哪些是惰性的,以避免用户混淆。特别值得注意的是,并非所有用户都能一次看到页面的所有部分;例如,屏幕阅读器用户、小型设备用户或放大镜用户,甚至使用特别小窗口的用户可能无法看到页面的活动部分,如果惰性部分不明显,他们可能会感到沮丧。

HTMLElement/inert

在所有当前引擎中受支持。

Firefox112+Safari15.5+Chrome102+
Opera?Edge102+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

inert IDL 属性必须 反映 同名内容属性。

6.4 跟踪 用户激活

为了防止滥用某些可能对用户造成困扰的 API(例如,打开弹出窗口或振动手机),用户代理只允许在用户主动与网页交互或至少与网页交互过一次时使用这些 API。这种“主动交互”状态通过本节定义的机制维护。

依赖用户激活的 API 分为不同的级别

粘性激活门控 API

这些 API 要求 粘性激活 状态为真,因此在第一次用户激活之前,它们会被阻塞。

瞬时激活门控 API

这些 API 要求 瞬时激活 状态为真,但它们不会 消耗 它,因此在瞬态状态 过期 之前,每个用户激活都允许多次调用。

瞬时激活消耗 API

这些 API 要求 瞬时激活 状态为真,并且它们在每次调用时 消耗用户激活,以防止每个用户激活多次调用。

历史动作激活消耗 API

这些 API 要求 历史动作激活 状态为真,并且它们在每次调用时 消耗历史动作用户激活,以防止每个用户激活多次调用。

6.4.1 UserActivation 接口

UserActivation

FirefoxNoSafari16.4+Chrome72+
Opera?Edge79+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

每个 Window 都有一个 关联的 UserActivation,它是一个 UserActivation 对象。在创建 Window 对象时,其 关联的 UserActivation 必须设置为在 Window 对象的 相关领域 中创建的 新的 UserActivation 对象。

navigator.userActivation.hasBeenActive

Navigator/userActivation

FirefoxNoSafari16.4+Chrome72+
Opera?Edge79+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

UserActivation/hasBeenActive

FirefoxNoSafari16.4+Chrome72+
Opera?Edge79+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

返回窗口是否具有 粘性激活

navigator.userActivation.isActive

UserActivation/hasBeenActive

FirefoxNoSafari16.4+Chrome72+
Opera?Edge79+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

返回窗口是否具有 瞬时激活

6.5 元素的激活行为

HTML 中的某些元素具有 激活行为,这意味着用户可以激活它们。这始终是由 click 事件引起的。

element.click()

就像元素被点击一样。

6.5.1 ToggleEvent 接口

event.oldState

ToggleEvent/oldState

在所有当前引擎中受支持。

Firefox🔰 114+Safari17+Chrome114+
Opera?Edge114+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

在从关闭状态转换为打开状态时设置为“closed”,或在从打开状态转换为关闭状态时设置为“open”。

event.newState

ToggleEvent/newState

在所有当前引擎中受支持。

Firefox🔰 114+Safari17+Chrome114+
Opera?Edge114+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

在从关闭状态转换为打开状态时设置为“open”,或在从打开状态转换为关闭状态时设置为“closed”。

oldStatenewState 属性必须返回它们初始化时的值。

一个 切换任务跟踪器 是一个 结构,它具有

任务
一个 任务,它触发 ToggleEvent
旧状态
一个字符串,它代表 任务 的事件的 oldState 属性的值。

6.6 焦点

6.6.1 简介

HTML 用户界面通常由多个交互式小部件组成,例如表单控件、可滚动区域、链接、对话框、浏览器选项卡等等。这些小部件形成了一个层次结构,其中一些小部件(例如浏览器选项卡、对话框)包含其他小部件(例如链接、表单控件)。

当使用键盘与界面交互时,按键输入从系统通过交互式小部件的层次结构传递到一个活动小部件,该小部件被称为 获得焦点

考虑一个在运行在图形环境中的浏览器选项卡中运行的 HTML 应用程序。假设这个应用程序有一个页面,其中有一些文本控件和链接,并且当前显示了一个模态对话框,对话框本身有一个文本控件和一个按钮。

在这种情况下,可聚焦小部件的层次结构将包括浏览器窗口,其子级中将有包含 HTML 应用程序的浏览器选项卡。选项卡本身将以链接和文本控件以及对话框作为子级。对话框本身将以文本控件和按钮作为子级。

如果在这个示例中,获得 焦点 的小部件是对话框中的文本控件,那么按键输入将从图形系统传递到 ① 网页浏览器,然后传递到 ② 选项卡,然后传递到 ③ 对话框,最后传递到 ④ 文本控件。

键盘事件始终针对这个 获得焦点 的元素。

6.6.2 数据模型

一个 顶级可遍历 当它可以接收从操作系统传递来的,可能针对其一个 活动文档后代可遍历 的键盘输入时,就拥有 系统焦点

一个 顶级可遍历 当其 系统可见性状态 为“visible”,并且它要么拥有 系统焦点,要么与它直接相关的用户代理小部件可以接收从操作系统传递来的键盘输入时,就拥有 用户注意力

当浏览器窗口失去焦点时,用户注意力就会消失,而系统焦点也可能消失到浏览器窗口中的其他系统小部件,例如地址栏。

一个 Document dd完全活动 并且 d节点可遍历顶级可遍历 拥有 用户注意力 时,就是一个 具有用户注意力的顶级可遍历的完全活动后代

术语 可聚焦区域 用于指代界面中可以进一步成为此类键盘输入目标的区域。可聚焦区域可以是元素、元素的一部分,或用户代理管理的其他区域。

每个 可聚焦区域 都有一个 DOM 锚点,它是一个 Node 对象,它代表 可聚焦区域 在 DOM 中的位置。(当 可聚焦区域 本身是一个 Node 时,它就是它自己的 DOM 锚点。)DOM 锚点 在某些 API 中用作 可聚焦区域 的替代,当没有其他 DOM 对象来表示 可聚焦区域 时。

下表描述了哪些对象可以是 可聚焦区域。左列的单元格描述了可以是 可聚焦区域 的对象;右列的单元格描述了这些元素的 DOM 锚点。(跨越两列的单元格是非规范性示例。)

可聚焦区域 DOM 锚点
示例
满足以下所有条件的元素 元素本身。

iframedialog<input type=text>,有时 <a href="">(取决于平台约定)。

与正在 渲染 且不是 惰性img 元素关联的 图像地图area 元素的形状。img 元素。

在以下示例中,area 元素在每个图像上创建一个形状。第一个形状的 DOM 锚点 是第一个 img 元素,第二个形状的 DOM 锚点 是第二个 img 元素。

<map id=wallmap><area alt="Enter Door" coords="10,10,100,200" href="door.html"></map>
...
<img src="images/innerwall.jpeg" alt="There is a white wall here, with a door." usemap="#wallmap">
...
<img src="images/outerwall.jpeg" alt="There is a red wall here, with a door." usemap="#wallmap">
正在 渲染 且不是 实际禁用惰性 的元素的用户代理提供的子部件。可聚焦区域 是子部件的元素。

video 元素的 用户界面中的控件,旋转控制版本的 <input type=number> 中的向上和向下按钮,details 元素渲染中允许使用键盘输入打开或关闭元素的部分。

正在 渲染 且不是 惰性 的元素的可滚动区域。为创建可滚动区域的框创建的元素。

CSS 'overflow' 属性的 'scroll' 值通常会创建一个可滚动区域。

具有非空 浏览上下文 且不是 惰性Document视窗为创建 视窗Document

iframe 的内容。

用户代理认定为可聚焦区域的任何其他元素或元素部分,特别是为了帮助进行辅助功能或更好地匹配平台约定。元素。

用户代理可以使所有列表项项目符号 按顺序可聚焦,以便用户可以更轻松地浏览列表。

类似地,用户代理可以使所有具有 title 属性的元素 按顺序可聚焦,以便可以访问其咨询信息。

可导航容器(例如 iframe)是 可聚焦区域,但路由到 可导航容器 的按键事件会立即路由到其 内容可导航活动文档。类似地,在按顺序聚焦导航中,可导航容器 本质上仅仅充当其 内容可导航活动文档 的占位符。


每个 Document 中的一个 可聚焦区域 被指定为 文档的聚焦区域。根据本规范中的算法,哪个控件被指定为会随着时间的推移而改变。

即使文档不是 完全活动 且未显示给用户,它仍然可以具有 文档的聚焦区域。如果文档的 完全活动 状态发生变化,其 文档的聚焦区域 将保持不变。

顶级可遍历的当前聚焦区域 traversable 是此算法返回的 可聚焦区域 或 null。

  1. 如果 traversable 没有 系统聚焦,则返回 null。

  2. candidatetraversable活动文档

  3. 只要 candidate聚焦区域 是具有非空 内容可导航可导航容器:将 candidate 设置为该 可导航容器内容可导航活动文档

  4. 如果 candidate聚焦区域 不为空,则将 candidate 设置为 candidate聚焦区域

  5. 返回 candidate

顶级可遍历的当前聚焦链 traversabletraversable当前聚焦区域聚焦链,如果 traversable 不为空,否则为空列表。

作为 可聚焦区域DOM 锚点 的元素被称为在该 可聚焦区域 成为 顶级可遍历的当前聚焦区域获得聚焦。当元素是 顶级可遍历的当前聚焦区域可聚焦区域DOM 锚点 时,它被认为是 聚焦 的。

6.6.3 tabindex 属性

Global_attributes/tabindex

在所有当前引擎中受支持。

Firefox1.5+Safari4+Chrome1+
Opera?Edge79+
Edge (Legacy)12+Internet ExplorerYes
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

tabindex 内容属性允许作者使元素及其以元素为 DOM 锚点 的区域成为 可聚焦区域,允许或阻止它们被 按顺序可聚焦,并确定它们在 按顺序聚焦导航 中的相对顺序。

名称“tab 索引”源于 Tab 键用于在可聚焦元素之间导航的常见用法。术语“tabbing”是指在 按顺序可聚焦可聚焦区域 中向前移动。

如果指定了 tabindex 属性,则其值必须是 有效整数。正数指定元素的 可聚焦区域按顺序聚焦导航顺序 中的相对位置,而负数则表示控件不是 按顺序可聚焦 的。

开发者在为其 tabindex 属性使用除 0 或 −1 以外的值时应谨慎,因为这样做很复杂。

以下提供了 tabindex 属性值的可能行为的摘要。

省略(或非整数的值)
用户代理将决定元素是否 可聚焦,以及如果是,它是否 按顺序可聚焦点击可聚焦(或两者都是)。
−1(或其他负整数的值)
使元素 可聚焦,并表明作者希望元素是 点击可聚焦,但不是 按顺序可聚焦。用户代理可能会忽略这种对点击和按顺序可聚焦性的偏好,例如,根据平台约定,对特定元素类型,或者对仅使用键盘的用户。
0
使元素 可聚焦,并表明作者希望元素是 点击可聚焦按顺序可聚焦。用户代理可能会忽略这种对点击和按顺序可聚焦性的偏好。
正整数的值
行为与 0 相同,但此外还在 tabindex 顺序聚焦导航范围 内创建了相对顺序,因此具有更高 tabindex 属性值的元素在后面出现。

请注意,tabindex 属性不能用于使元素不可聚焦。页面作者执行此操作的唯一方法是 禁用 元素或使其 惰性

6.6.4 聚焦管理 API

documentOrShadowRoot.activeElement

返回文档中按键事件被路由到的最深元素。大致来说,这是文档中的聚焦元素。

在本 API 中,当一个 子可导航元素 获得焦点时,其 容器 在其 父级活动文档 中获得 焦点。例如,如果用户将焦点移动到 iframe 中的文本控件,则 iframe 是由 activeElement API 在 iframe节点文档 中返回的元素。

类似地,当获得焦点的元素位于与 documentOrShadowRoot 不同的 节点树 中时,如果 documentOrShadowRoot 是获得焦点元素的 包含阴影的祖先,则返回的元素将是位于与 documentOrShadowRoot 相同 节点树 中的 宿主,否则为 null。

document.hasFocus()

如果键盘事件正在通过或路由到文档,则返回 true;否则,返回 false。大致来说,这对应于文档或嵌套在这个文档内的文档获得焦点。

window.focus()

将焦点移动到窗口的 可导航元素(如果有)。

element.focus([ { preventScroll: true } ])

将焦点移动到元素。

如果元素是 可导航容器,则将焦点移动到其 内容可导航元素

默认情况下,此方法还会将元素滚动到视图中。提供 preventScroll 选项并将其设置为 true 可以防止这种行为。

element.blur()

将焦点移动到 视区。不建议使用此方法;如果你想将焦点放在 视区 上,请在 Document文档元素 上调用 focus() 方法。

如果你觉得焦点环很丑,不要使用此方法来隐藏焦点环。相反,使用 :focus-visible 伪类来覆盖 'outline' 属性,并提供其他方法来显示哪个元素获得焦点。请注意,如果不可用替代的聚焦样式,则页面对于主要使用键盘导航页面的人或视觉障碍人士(使用焦点轮廓帮助他们导航页面)而言,其可用性将大大降低。

例如,要隐藏 textarea 元素的轮廓,并使用黄色背景来指示焦点,你可以使用

textarea:focus-visible { outline: none; background: yellow; color: black; }

6.6.5 The autofocus attribute

The autofocus content attribute allows the author to indicate that an element is to be focused as soon as the page is loaded, allowing the user to just start typing without having to manually focus the main element.

When the autofocus attribute is specified on an element inside dialog elements or HTML elements whose popover attribute is set, then it will be focused when the dialog or popover becomes shown.

The autofocus attribute is a boolean attribute.

To find the nearest ancestor autofocus scoping root element given an Element element

  1. If element is a dialog element, then return element.

  2. If element's popover attribute is not in the no popover state, then return element.

  3. Let ancestor be element.

  4. While ancestor has a parent element

    1. Set ancestor to ancestor's parent element.

    2. If ancestor is a dialog element, then return ancestor.

    3. If ancestor's popover attribute is not in the no popover state, then return ancestor.

  5. Return ancestor.

There must not be two elements with the same nearest ancestor autofocus scoping root element that both have the autofocus attribute specified.

In the following snippet, the text control would be focused when the document was loaded.

<input maxlength="256" name="q" value="" autofocus>
<input type="submit" value="Search">

The autofocus attribute applies to all elements, not just to form controls. This allows examples such as the following

<div contenteditable autofocus>Edit <strong>me!</strong><div>

6.7 Assigning keyboard shortcuts

6.7.1 Introduction

Each element that can be activated or focused can be assigned a single key combination to activate it, using the accesskey attribute.

The exact shortcut is determined by the user agent, based on information about the user's keyboard, what keyboard shortcuts already exist on the platform, and what other shortcuts have been specified on the page, using the information provided in the accesskey attribute as a guide.

In order to ensure that a relevant keyboard shortcut is available on a wide variety of input devices, the author can provide a number of alternatives in the accesskey attribute.

Each alternative consists of a single character, such as a letter or digit.

User agents can provide users with a list of the keyboard shortcuts, but authors are encouraged to do so also. The accessKeyLabel IDL attribute returns a string representing the actual key combination assigned by the user agent.

In this example, an author has provided a button that can be invoked using a shortcut key. To support full keyboards, the author has provided "C" as a possible key. To support devices equipped only with numeric keypads, the author has provided "1" as another possible key.

<input type=button value=Collect onclick="collect()"
       accesskey="C 1" id=c>

To tell the user what the shortcut key is, the author has this script here opted to explicitly add the key combination to the button's label

function addShortcutKeyLabel(button) {
  if (button.accessKeyLabel != '')
    button.value += ' (' + button.accessKeyLabel + ')';
}
addShortcutKeyLabel(document.getElementById('c'));

Browsers on different platforms will show different labels, even for the same key combination, based on the convention prevalent on that platform. For example, if the key combination is the Control key, the Shift key, and the letter C, a Windows browser might display "Ctrl+Shift+C", whereas a Mac browser might display "^⇧C", while an Emacs browser might just display "C-C". Similarly, if the key combination is the Alt key and the Escape key, Windows might use "Alt+Esc", Mac might use "⌥⎋", and an Emacs browser might use "M-ESC" or "ESC ESC".

In general, therefore, it is unwise to attempt to parse the value returned from the accessKeyLabel IDL attribute.

6.7.2 The accesskey attribute

Global_attributes/accesskey

在所有当前引擎中受支持。

Firefox1+Safari4+Chrome1+
Opera?Edge79+
Edge (Legacy)12+Internet ExplorerYes
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

All HTML elements may have the accesskey content attribute set. The accesskey attribute's value is used by the user agent as a guide for creating a keyboard shortcut that activates or focuses the element.

If specified, the value must be an ordered set of unique space-separated tokens none of which are identical to another token and each of which must be exactly one code point in length.

In the following example, a variety of links are given with access keys so that keyboard users familiar with the site can more quickly navigate to the relevant pages

<nav>
 <p>
  <a title="Consortium Activities" accesskey="A" href="/Consortium/activities">Activities</a> |
  <a title="Technical Reports and Recommendations" accesskey="T" href="/TR/">Technical Reports</a> |
  <a title="Alphabetical Site Index" accesskey="S" href="/Consortium/siteindex">Site Index</a> |
  <a title="About This Site" accesskey="B" href="/Consortium/">About Consortium</a> |
  <a title="Contact Consortium" accesskey="C" href="/Consortium/contact">Contact</a>
 </p>
</nav>

In the following example, the search field is given two possible access keys, "s" and "0" (in that order). A user agent on a device with a full keyboard might pick Ctrl + Alt + S as the shortcut key, while a user agent on a small device with just a numeric keypad might pick just the plain unadorned key 0

<form action="/search">
 <label>Search: <input type="search" name="q" accesskey="s 0"></label>
 <input type="submit">
</form>

In the following example, a button has possible access keys described. A script then tries to update the button's label to advertise the key combination the user agent selected.

<input type=submit accesskey="N @ 1" value="Compose">
...
<script>
 function labelButton(button) {
   if (button.accessKeyLabel)
     button.value += ' (' + button.accessKeyLabel + ')';
 }
 var inputs = document.getElementsByTagName('input');
 for (var i = 0; i < inputs.length; i += 1) {
   if (inputs[i].type == "submit")
     labelButton(inputs[i]);
 }
</script>

On one user agent, the button's label might become "Compose (⌘N)". On another, it might become "Compose (Alt+⇧+1)". If the user agent doesn't assign a key, it will be just "Compose". The exact string depends on what the assigned access key is, and on how the user agent represents that key combination.

6.8 Editing

6.8.1 Making document regions editable: The contenteditable content attribute

HTMLElement/contentEditable

在所有当前引擎中受支持。

Firefox3+Safari3+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+Internet Explorer5.5+
Firefox Android?Safari iOS1+Chrome Android?WebView Android?Samsung Internet?Opera Android10.1+

Global_attributes/contenteditable

在所有当前引擎中受支持。

Firefox3+Safari4+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+Internet Explorer5.5+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

contenteditable 内容属性 是一个 枚举属性,具有以下关键字和状态

关键字状态简要描述
true true 元素可编辑。
(空字符串)
false false 元素不可编辑。
plaintext-only plaintext-only 仅元素的原始文本内容可编辑;富文本格式被禁用。

该属性的 缺失值默认值无效值默认值 都是 inherit 状态。inherit 状态表示元素的可编辑性(或不可编辑性)基于父元素的状态。

例如,考虑一个页面,该页面包含一个 form 元素和一个 textarea 元素,用于发布新文章,其中用户预期使用 HTML 编写文章。

<form method=POST>
 <fieldset>
  <legend>New article</legend>
  <textarea name=article>&lt;p>Hello world.&lt;/p></textarea>
 </fieldset>
 <p><button>Publish</button></p>
</form>

当启用脚本时,可以使用 contenteditable 属性将 textarea 元素替换为富文本控件。

<form method=POST>
 <fieldset>
  <legend>New article</legend>
  <textarea id=textarea name=article>&lt;p>Hello world.&lt;/p></textarea>
  <div id=div style="white-space: pre-wrap" hidden><p>Hello world.</p></div>
  <script>
   let textarea = document.getElementById("textarea");
   let div = document.getElementById("div");
   textarea.hidden = true;
   div.hidden = false;
   div.contentEditable = "true";
   div.oninput = (e) => {
     textarea.value = div.innerHTML;
   };
  </script>
 </fieldset>
 <p><button>Publish</button></p>
</form>

要启用的功能(例如,插入链接)可以使用 document.execCommand() API 实现,也可以使用 Selection API 和其他 DOM API 实现。 [EXECCOMMAND] [SELECTION] [DOM]

contenteditable 属性也可以非常有效地使用。

<!doctype html>
<html lang=en>
<title>Live CSS editing!</title>
<style style=white-space:pre contenteditable>
html { margin:.2em; font-size:2em; color:lime; background:purple }
head, title, style { display:block }
body { display:none }
</style>
element.contentEditable [ = value ]

根据 contenteditable 属性的状态返回 "true"、"plaintext-only"、"false" 或 "inherit"。

可以设置,以更改该状态。

如果新值不是这些字符串之一,则会抛出一个 "SyntaxError" DOMException

element.isContentEditable

如果元素可编辑,则返回 true;否则,返回 false。

6.8.2 使整个文档可编辑:designMode getter 和 setter

document.designMode [ = value ]

如果文档可编辑,则返回 "on";否则,返回 "off"。

可以设置,以更改文档的当前状态。这会使文档获得焦点,并重置该文档中的选择。

6.8.3 页面内编辑器的最佳实践

鼓励作者在 编辑宿主 以及通过这些编辑机制最初创建的标记上设置 'white-space' 属性的值为 'pre-wrap'。默认的 HTML 空白处理不适合 WYSIWYG 编辑,如果 'white-space' 保持其默认值,则某些特殊情况下行换行将无法正常工作。

例如,如果使用默认的 'normal' 值,则会发生以下问题:考虑用户输入 "yellow␣␣ball" 的情况,单词之间有两个空格(这里用 "␣" 表示)。使用针对 'white-space' 默认值('normal')的编辑规则,生成的标记将包含 "yellow&nbsp; ball" 或 "yellow &nbsp;ball";也就是说,除了常规空格之外,两个单词之间还会有一个不间断空格。这是因为 'white-space' 的 'normal' 值要求将相邻的常规空格合并在一起。

在前面一种情况下,"yellow⍽" 可能会换行到下一行("⍽" 用于表示不间断空格),即使 "yellow" 本身可能适合放在行的末尾;在后面一种情况下,"⍽ball"(如果换行到行的开头)将会有来自不间断空格的可见缩进。

然而,当将 'white-space' 设置为 'pre-wrap' 时,编辑规则将改为简单地在单词之间放置两个常规空格,如果这两个单词在行的末尾被拆分,则空格将被整齐地从渲染中移除。

6.8.4 拼写和语法检查

Global_attributes/spellcheck

在所有当前引擎中受支持。

FirefoxYesSafariYesChrome9+
OperaYesEdge79+
Edge (Legacy)12+Internet Explorer11
Firefox Android57+Safari iOS9.3+Chrome Android47+WebView Android?Samsung Internet?Opera Android37+

spellcheck 内容属性 是一个 枚举属性,具有以下关键字和状态

关键字状态简要描述
true true 将检查拼写和语法。
(空字符串)
false false 不会检查拼写和语法。

该属性的 缺失值默认值无效值默认值 都是 default 状态。default 状态表示该元素应该根据默认行为进行操作,可能基于父元素的自身 spellcheck 状态,如下所述。

element.spellcheck [ = value ]

如果元素应该检查其拼写和语法,则返回 true;否则,返回 false。

可以设置,以覆盖默认值并设置 spellcheck 内容属性。

本规范没有定义拼写和语法检查的用户界面。用户代理可以提供按需检查,可以在启用检查时执行持续检查,也可以使用其他界面。

6.8.5 书写建议

用户代理在用户键入可编辑区域时提供书写建议,无论是在表单控件(例如 textarea 元素)中,还是在 编辑宿主 中的元素中。

writingsuggestions 内容属性 是一个 枚举属性,具有以下关键字和状态

关键字状态简要描述
true true 应该在这个元素上提供书写建议。
(空字符串)
false false 不应该在这个元素上提供书写建议。

该属性的 缺失值默认值default 状态。default 状态表示该元素应该根据默认行为进行操作,可能基于父元素的自身 writingsuggestions 状态,如下所述。

该属性的 无效值默认值true 状态。

element.writingSuggestions [ = value ]

如果用户代理应该在元素的范围内提供书写建议,则返回 "true";否则,返回 "false"。

可以设置,以覆盖默认值并设置 writingsuggestions 内容属性。


用户代理应该只在元素的范围内提供建议,如果对给定 element 运行以下算法的结果为 true,则应该只在元素的范围内提供建议。

  1. 如果用户禁用了书写建议,则返回 false。

  2. 如果以下条件都不满足

    则返回 false。

  3. 如果 element 有一个 包含祖先,其 writingsuggestions 内容属性不处于 default 状态,并且最近的此类祖先的 writingsuggestions 内容属性处于 false 状态,则返回 false。

  4. 否则,返回 true。

本规范没有定义书写建议的用户界面。用户代理可以提供按需建议、用户键入时的连续建议、内联建议、弹出窗口中的自动填充式建议,也可以使用其他界面。

6.8.6 自动大写

一些文本输入方法,例如移动设备上的虚拟键盘以及语音输入,通常通过自动将句子首字母大写来帮助用户(当用这种约定编写文本时)。实现自动大写的虚拟键盘可能会在即将键入需要自动大写的字母时自动切换到显示大写字母(但允许用户切换回小写字母)。其他类型的输入,例如语音输入,可能会以一种不提供用户先进行干预选项的方式执行自动大写。autocapitalize 属性允许作者控制此类行为。

在典型的实现中,autocapitalize 属性不会影响物理键盘输入的行为。(出于这个原因,以及用户在某些情况下可以覆盖自动大写行为或在初始输入后编辑文本,因此不应将该属性用于任何类型的输入验证。)

可以在 编辑宿主 上使用 autocapitalize 属性来控制托管可编辑区域的自动大写行为,也可以在 inputtextarea 元素上使用该属性来控制向该元素输入文本的行为,或者在 form 元素上使用该属性来控制与 form 元素关联的所有 继承自动大写和自动更正的元素 的默认行为。

autocapitalize 属性绝不会为 input 元素启用自动大写,这些元素的 type 属性处于以下状态之一:URL电子邮件密码

自动大写处理模型基于在五个 自动大写提示 中进行选择,定义如下

default

用户代理和输入法应自行决定是否启用自动大写。

none

不应应用自动大写(所有字母应默认为小写)。

sentences

每个句子的第一个字母应默认为大写字母;所有其他字母应默认为小写字母。

words

每个单词的第一个字母应默认为大写字母;所有其他字母应默认为小写字母。

characters

所有字母应默认为大写。

Global_attributes/autocapitalize

在所有当前引擎中受支持。

Firefox111+Safari不支持Chrome43+
Opera?Edge79+
Edge (Legacy)?Internet Explorer?
Firefox Android?Safari iOS5+Chrome Android?WebView Android?Samsung Internet?Opera Android?

autocapitalize 属性是一个 枚举属性,其状态是所有可能的 自动大写提示。该属性状态指定的 自动大写提示 与其他因素相结合,形成 使用的自动大写提示,用于告知用户代理的行为。该属性的关键字及其状态映射如下

关键字状态
off none
none
on sentences
sentences
words words
characters characters

该属性的 缺失值默认值default 状态,其 无效值默认值sentences 状态。

element.autocapitalize [ = value ]

返回元素的当前自动大写状态,如果未设置,则返回空字符串。请注意,对于 inputtextarea 元素,它们从 form 元素继承状态,这将返回 form 元素的自动大写状态,但对于可编辑区域中的元素,这将不会返回编辑宿主的自动大写状态(除非该元素实际上是 编辑宿主)。

可以设置,以设置 autocapitalize 内容属性(并因此更改元素的自动大写行为)。

6.8.7 自动更正

某些输入文本的方法通过自动更正拼写错误的单词来辅助用户,此过程也称为自动更正。用户代理可以支持对可编辑文本进行自动更正,无论是表单控件(例如 textarea 元素的值),还是 编辑宿主 中的元素(例如,使用 contenteditable)。自动更正可能伴随着用户界面,指示文本即将被自动更正或已被自动更正,并且通常在插入标点符号、空格或拼写错误单词后的新段落时执行。 autocorrect 属性允许作者控制这种行为。

可以在编辑宿主上使用 autocorrect 属性来控制托管可编辑区域的自动更正行为,也可以在 inputtextarea 元素上使用该属性来控制向该元素插入文本时的行为,或者在 form 元素上使用该属性来控制与 form 元素关联的所有 继承自动大写和自动更正的元素 的默认行为。

autocorrect 属性绝不会为 input 元素启用自动更正,这些元素的 type 属性处于以下状态之一:URL电子邮件密码

autocorrect 属性是一个枚举属性,具有以下关键字和状态

关键字状态简要描述
on on 用户代理可以在用户键入时自动更正拼写错误。用户代理是否在键入时自动更正拼写由用户代理决定,并且可能取决于元素以及用户的首选项。
(空字符串)
off off 用户代理不允许在用户键入时自动更正拼写。

该属性的 无效值默认值缺失值默认值 都是 on 状态。

autocorrect 获取器步骤:如果元素的 使用的自动更正状态on,则返回 true;如果元素的 使用的自动更正状态off,则返回 false。设置器步骤:如果给定值为 true,则元素的 autocorrect 属性必须设置为 "on";否则必须设置为 "off"。

要计算元素 element使用的自动更正状态,请运行以下步骤

  1. 如果 element 是一个 input 元素,其 type 属性处于以下状态之一:URL电子邮件密码 状态,则返回 off

  2. 如果 autocorrect 内容属性在 element 上存在,则返回该属性的状态。

  3. 如果 element 是一个 继承自动大写和自动更正的元素 并且具有非空 表单所有者,则返回 element表单所有者autocorrect 属性的状态。

  4. 返回 on

element . autocorrect

返回元素的自动更正行为。请注意,对于 继承自动大写和自动更正的元素,它们从 form 元素继承状态,这将返回 form 元素的自动更正行为,但对于可编辑区域中的元素,这将不会返回编辑宿主的自动更正行为(除非该元素实际上是 编辑宿主)。

element . autocorrect = value

更新 autocorrect 内容属性(并因此更改元素的自动更正行为)。

以下示例中的 input 元素将不允许自动更正,因为它没有 autocorrect 内容属性,因此从 form 元素继承,该元素具有 "off" 属性。但是, textarea 元素将允许自动更正,因为它具有 autocorrect 内容属性,其值为 "on"。

<form autocorrect="off">
 <input type="search">
 <textarea autocorrect="on"></textarea>
</form>

6.8.8 输入模式: inputmode 属性

用户代理可以在表单控件(例如 textarea 元素的值)或 编辑宿主 中的元素(例如,使用 contenteditable)上支持 inputmode 属性。

Global_attributes/inputmode

在所有当前引擎中受支持。

Firefox95+Safari不支持Chrome66+
Opera?Edge79+
Edge (Legacy)?Internet Explorer
Firefox Android79+Safari iOS12.2+Chrome Android?WebView Android?Samsung Internet?Opera Android?

inputmode 内容属性是一个 枚举属性,它指定对用户输入内容最有效的输入机制类型。

关键字Description
none 用户代理不应显示虚拟键盘。此关键字适用于呈现自身键盘控件的内容。
text 用户代理应显示能够以用户区域设置进行文本输入的虚拟键盘。
tel 用户代理应该显示一个能够输入电话号码的虚拟键盘。这应该包括数字 0 到 9 的键、"#" 字符和 "*" 字符。在某些语言环境中,这也可以包括字母助记标签(例如,在美国,标记为“2”的键在历史上也标记为字母 A、B 和 C)。
url 用户代理应该显示一个能够在用户语言环境中输入文本的虚拟键盘,带有帮助输入 URL 的键,例如 "/" 和 "." 字符的键,以及用于快速输入域名中常用的字符串(如 "www." 或 ".com")的键。
email 用户代理应该显示一个能够在用户语言环境中输入文本的虚拟键盘,带有帮助输入电子邮件地址的键,例如 "@" 字符和 "." 字符的键。
numeric 用户代理应该显示一个能够输入数字的虚拟键盘。此关键字适用于 PIN 输入。
decimal 用户代理应该显示一个能够输入小数的虚拟键盘。应该显示数字键和语言环境的格式分隔符。
search 用户代理应该显示一个针对搜索优化的虚拟键盘。

6.8.9 输入模式:enterkeyhint 属性

用户代理可以支持表单控件(例如 textarea 元素的值)或编辑宿主中的元素(例如,使用 contenteditable)上的 enterkeyhint 属性。

Global_attributes/enterkeyhint

在所有当前引擎中受支持。

Firefox94+Safari13.1+Chrome77+
Opera66+Edge79+
Edge (Legacy)?Internet Explorer
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android57+

enterkeyhint 内容属性是一个 枚举属性,它指定了要在虚拟键盘上为 Enter 键呈现的操作标签(或图标)。这允许作者自定义 Enter 键的呈现方式,以使其对用户更有用。

关键字Description
enter 用户代理应该为“enter”操作呈现一个提示,通常是插入一个新行。
done 用户代理应该为“done”操作呈现一个提示,通常表示没有更多内容要输入,输入法编辑器 (IME) 将关闭。
go 用户代理应该为“go”操作呈现一个提示,通常表示将用户带到他们输入的文本的目标位置。
next 用户代理应该为“next”操作呈现一个提示,通常将用户带到下一个可以接受文本的字段。
previous 用户代理应该为“previous”操作呈现一个提示,通常将用户带到上一个可以接受文本的字段。
search 用户代理应该为“search”操作呈现一个提示,通常将用户带到他们输入的文本的搜索结果。
send 用户代理应该为“send”操作呈现一个提示,通常将文本传递到其目标。

6.9 页面内查找

6.9.1 简介

本节定义了 页面内查找——一种常见的用户代理机制,允许用户在页面内容中搜索特定信息。

页面内查找 功能的访问是通过 页面内查找界面 提供的。这是一个用户代理提供的用户界面,允许用户指定输入和搜索参数。此界面可能作为快捷方式或菜单选择的结果出现。

页面内查找界面 中的文本输入和设置的组合代表用户 查询。这通常包括用户想要搜索的文本,以及可选设置(例如,可以限制搜索仅限于完整单词)。

用户代理会为给定的 查询 处理页面内容,并识别零个或多个 匹配,这些匹配是满足用户 查询 的内容范围。

其中一个 匹配 被识别为用户的 活动匹配。它会被高亮显示并滚动到视图中。用户可以通过使用 页面内查找界面 推进 活动匹配 来浏览 匹配

问题 #3539 跟踪了对当前未指定的 window.find() API 的页面内查找机制的标准化。

6.9.2detailshidden=until-found 的交互

当页面内查找开始搜索匹配项时,页面中所有没有设置 open 属性的 details 元素,其第二个插槽的 跳过内容 应该变得可访问,而无需修改 open 属性,以使页面内查找能够在其中搜索。类似地,所有具有 隐藏直到找到 状态的 hidden 属性的 HTML 元素,其 跳过内容 应该变得可访问,而无需修改 hidden 属性,以使页面内查找能够在其中搜索。在页面内查找完成搜索匹配项后,details 元素和具有 隐藏直到找到 状态的 hidden 属性的元素,其内容应该再次变得跳过。整个过程必须同步发生(因此对用户或作者代码不可见)。[CSSCONTAIN]

当页面内查找选择新的 活动匹配 时,执行以下步骤

  1. node活动匹配 中的第一个节点。

  2. 在用户交互任务源为给定 node 的相关全局对象排队一个全局任务,以运行以下步骤

    1. node 上运行 祖先 details 元素揭示算法

    2. node 上运行 祖先 hidden-until-found 元素揭示算法

当页面内查找像这样自动展开 details 元素时,它将触发 toggle 事件。与页面内查找触发的单独的 scroll 事件一样,页面可以使用此事件来发现用户在页面内查找对话框中输入的内容。如果页面创建一个带有当前搜索词的小型可滚动区域,并将用户可能输入的每个可能的下一个字符用间隙隔开,并观察浏览器滚动到的字符,它可以将该字符添加到搜索词中并更新可滚动区域以逐步构建搜索词。通过将每个可能的下一个匹配项包装在一个封闭的 details 元素中,页面可以监听 toggle 事件,而不是 scroll 事件。可以通过不针对用户在页面内查找对话框中输入的每个字符进行操作来解决针对这两种事件的攻击。

6.9.3 与选择的交互

页面内查找过程是在文档的上下文中调用的,并且可能会对该文档的 选择 产生影响。具体来说,定义 活动匹配 的范围可以决定当前的选择。但是,这些选择更新可以在页面内查找过程中的不同时间发生(例如,在 页面内查找界面 关闭时,或者在 活动匹配 范围更改时)。

6.10 关闭请求和关闭观察者

6.10.1 关闭请求

以一种 实现定义的(并且可能是设备特定的)方式,用户可以向用户代理发送 关闭请求。这表示用户希望关闭当前显示在屏幕上的内容,例如弹出窗口、菜单、对话框、选择器或显示模式。

一些关闭请求示例:

在按下 Esc 键被解释为 关闭请求 的平台上,用户代理必须将键按下解释为关闭请求,而不是键被释放时。因此,在上面的算法中,触发的“相关事件”必须是单个 keydown 事件。

Esc 键被用作 关闭请求 的平台上,用户代理将首先触发一个适当初始化的 keydown 事件。如果 Web 开发人员通过调用 preventDefault() 取消了该事件,则不会发生任何后续操作。但如果事件触发且未被取消,则用户代理将继续 处理关闭观察器

在后退按钮可能被用作 关闭请求 的平台上,不会涉及任何事件。因此,当按下后退按钮时,用户代理将直接继续 处理关闭观察器。如果存在 活动关闭观察器,则该观察器将被触发。如果没有,用户代理可以以其他方式解释后退按钮的按下操作,例如将其解释为 按 -1 的增量遍历历史记录 的请求。

6.10.2 CloseWatcher 接口

watcher = new CloseWatcher()
watcher = new CloseWatcher({ signal })

创建一个新的 CloseWatcher 实例。

如果提供了 signal 选项,则可以通过中止给定的 AbortSignal 来销毁 watcher(如同通过 watcher.destroy() 销毁)。

如果任何 关闭观察器 已经处于活动状态,且 Window 没有 历史记录动作激活,则响应任何 关闭请求,生成的 CloseWatcher 将与该已经处于活动状态的 关闭观察器 一起关闭。(这个已经处于活动状态的 关闭观察器 不一定需要是 CloseWatcher 对象;它可以是模态的 dialog 元素,或者是由具有 popover 属性的元素生成的弹出框。)

watcher.requestClose()

如同发送了一个针对 watcher关闭请求,首先触发 cancel 事件,如果该事件没有通过 preventDefault() 被取消,则继续触发 close 事件,然后如同调用了 watcher.destroy() 一样停用关闭观察器。

这是一个帮助程序实用程序,可以通过让所有非 关闭请求 的关闭方式调用此方法,将取消和关闭逻辑整合到 cancelclose 事件处理程序中。

watcher.close()

立即触发 close 事件,然后如同调用了 watcher.destroy() 一样停用关闭观察器。

这是一个帮助程序实用程序,用于将关闭逻辑触发到 close 事件处理程序中,跳过 cancel 事件处理程序中的任何逻辑。

watcher.destroy()

停用 watcher,使其不再接收 close 事件,并且可以构建新的独立的 CloseWatcher 实例。

如果相关 UI 元素以某种方式被拆除(而不是关闭),则应该调用此方法。

以下是所有实现 CloseWatcher 接口的对象支持的 事件处理程序(及其对应的 事件处理程序事件类型),作为 事件处理程序 IDL 属性

事件处理程序 事件处理程序事件类型
oncancel cancel
onclose close

如果想要实现一个自定义的拾取器控件,该控件在用户提供的 关闭请求 以及按下关闭按钮时关闭自身,则以下代码展示了如何使用 CloseWatcher API 来处理关闭请求

const watcher = new CloseWatcher();
const picker = setUpAndShowPickerDOMElement();

let chosenValue = null;

watcher.onclose = () => {
  chosenValue = picker.querySelector('input').value;
  picker.remove();
};

picker.querySelector('.close-button').onclick = () => watcher.requestClose();

请注意,如何将收集所选值的逻辑集中在 CloseWatcher 对象的 close 事件处理程序中,而关闭按钮的 click 事件处理程序通过调用 requestClose() 将其委派给该逻辑。

CloseWatcher 对象上的 cancel 事件可用于阻止 close 事件触发,以及阻止 CloseWatcher 被销毁。一个典型的用例如下:

watcher.oncancel = async (e) => {
  if (hasUnsavedData && e.cancelable) {
    e.preventDefault();

    const userReallyWantsToClose = await askForConfirmation("Are you sure you want to close?");
    if (userReallyWantsToClose) {
      hasUnsavedData = false;
      watcher.close();
    }
  }
};

出于防止滥用的目的,此事件只有在页面具有 历史记录动作激活 时才是 cancelable,而 历史记录动作激活 会在任何给定的 关闭请求 之后丢失。这确保了如果用户连续两次发送关闭请求,而没有任何用户激活操作,则该请求一定会成功;第二个请求会忽略任何 cancel 事件处理程序试图调用 preventDefault() 的操作,并继续关闭 CloseWatcher

综合以上两个例子,展示了 requestClose()close() 之间的区别。因为我们在关闭按钮的 click 事件处理程序中使用了 requestClose(),所以点击该按钮将触发 CloseWatchercancel 事件,因此如果存在未保存的数据,可能会询问用户是否确认。如果我们使用了 close(),则将跳过此检查。有时这是合适的,但通常 requestClose() 是用户触发的关闭请求的更好选择。

除了 cancel 事件的 用户激活 限制之外,在 CloseWatcher 的构建过程中还存在一种更微妙的用户激活限制。如果在没有用户激活的情况下创建了多个 CloseWatcher,则新创建的 CloseWatcher 将与最近创建的 关闭观察器 分组,以便单个 关闭请求 将同时关闭这两个观察器。

window.onload = () => {
  // This will work as normal: it is the first close watcher created without user activation.
  (new CloseWatcher()).onclose = () => { /* ... */ };
};

button1.onclick = () => {
  // This will work as normal: the button click counts as user activation.
  (new CloseWatcher()).onclose = () => { /* ... */ };
};

button2.onclick = () => {
  // These will be grouped together, and both will close in response to a single close request.
  (new CloseWatcher()).onclose = () => { /* ... */ };
  (new CloseWatcher()).onclose = () => { /* ... */ };
};

这意味着正确调用 destroy()close()requestClose() 很重要。这样做是恢复“免费”未分组关闭观察器插槽的唯一方法。此类在没有用户激活的情况下创建的关闭观察器适用于诸如会话非活动超时对话框或服务器触发的事件的紧急通知等情况,这些通知不是响应用户激活而生成的。