网页界面通常会隐藏内容,以改善用户体验、节省屏幕空间或提升网页性能。display: none 或 visibility: hidden 等传统方法可以从视觉上隐藏内容,但也会使屏幕阅读器和“在页面中查找”等浏览器功能完全无法访问这些内容。
若要隐藏内容,但仍允许用户搜索这些内容,并允许通过网址片段和“滚动到文本片段”链接深层链接到这些内容,您可以使用 HTML <details> 元素或 hidden="until-found" 属性。通常建议使用 <details> 元素,因为它更易于实现和维护,但在一些更复杂的情况下,<details> 并不够用,需要使用 hidden="until-found"。
例如:
- 如果您想完全控制显示/隐藏机制的样式。
- 如果用于显示/隐藏内容的界面控件位于 DOM 的其他部分。
- 如果您不想支持在内容显示后将其隐藏。
如何实现
<details> 元素默认具有可搜索和可访问的文本,无需进行特殊实现。如果可能,请优先使用 <details>,而不是 hidden="until-found"。
如果您需要改用 hidden="until-found",请按照以下说明操作:
- 应用属性:直接将
hidden="until-found"HTML 属性添加到包含应隐藏的内容的元素中。 - 同步界面状态:如果界面具有依赖于内容可见性的相关状态(例如,更新 ARIA 属性、切换打开/关闭 CSS 类或旋转折叠面板图标),请执行以下操作:
- 您必须为
beforematch事件添加事件监听器。 - 直接在带有
hidden="until-found"属性的元素上注册beforematch事件监听器。由于事件会冒泡,您也可以使用事件委托,在父元素(例如标签页容器)上注册单个监听器,以便一次性管理多个隐藏部分。 - 在事件监听器中,执行逻辑以同步相关界面元素(例如关闭其他打开的标签页或更改切换按钮的状态)。
- 您必须为
示例代码
目标:呈现一个隐藏的容器,其中的内容对用户保持不可见,直到用户在该部分中搜索某个字词。
使用 <details> 元素
<details>
<summary>Click to expand</summary>
<p>This content is visually hidden.</p>
</details>
互斥披露
处理互斥的内容区域(例如互斥的手风琴式折叠菜单)时,请使用具有共享 name 属性的原生 HTML <details> 元素。
<div class="accordion-group">
<!-- The name attribute creates an exclusive disclosure group -->
<details class="disclosure" name="my-accordion">
<summary>Section 1</summary>
<p>Section 1 content</p>
</details>
<details class="disclosure" name="my-accordion" open>
<summary>Section 2</summary>
<p>Section 2 content</p>
</details>
<details class="disclosure" name="my-accordion">
<summary>Section 3</summary>
<p>Section 3 content</p>
</details>
</div>
使用 hidden="until-found" 属性
<!-- The browser automatically removes hidden="until-found" upon a search match -->
<div class="hidden-container" hidden="until-found">
<p>This content is visually hidden.</p>
</div>
自定义互斥披露信息
处理由外部按钮控制的自定义互斥区域时,请确保仅保留匹配的面板可见。在 beforematch 事件处理脚本中,您必须同步相关的 ARIA 状态,例如在控制按钮上设置 aria-expanded="true"。
<div class="custom-accordion">
<div class="controls">
<button aria-expanded="true" aria-controls="panel-1" id="btn-1">Section 1</button>
<button aria-expanded="false" aria-controls="panel-2" id="btn-2">Section 2</button>
</div>
<div id="panel-1" class="panel">
<p>Section 1 content (visible)</p>
</div>
<div id="panel-2" class="panel" hidden="until-found">
<p>Section 2 content (hidden)</p>
</div>
</div>
const accordion = document.querySelector('.custom-accordion');
accordion.addEventListener('beforematch', (e) => {
// Hide all panels and synchronize button states before the browser reveals the matched panel
accordion.querySelectorAll('.panel').forEach((panel) => {
if (panel !== e.target) {
panel.hidden = 'until-found';
}
});
accordion.querySelectorAll('button').forEach((btn) => {
const controls = btn.getAttribute('aria-controls');
btn.setAttribute('aria-expanded', controls === e.target.id ? 'true' : 'false');
});
});
有关“hidden="until-found"”目标的最佳做法
- 务必将边框、内边距和背景应用于嵌套的子级封装容器,而不是直接应用于具有
hidden="until-found"属性的元素。这样可以防止在元素隐藏时发生意外的布局偏移或视觉残留。 - 请勿将
display: none、visibility: hidden或任何关联的display或visibilityCSS 属性直接应用于具有hidden="until-found"属性的元素。这会破坏原生功能,并使内容永久隐藏在搜索索引中。 - 请勿将
hidden="until-found"用于敏感信息、内部数据令牌或不应通过搜索公开的不相关数据。 - 请勿使用
hidden="until-found"替代“仅限屏幕阅读器”(.sr-only) 文本。
浏览器支持和后备策略
请勿因浏览器不支持而避免使用 hidden="until-found",因为其无障碍优势远大于实现后备方案的成本。
hidden="until-found" 后备
对于标准界面元素(例如折叠式菜单或“阅读更多”部分),请使用 JavaScript 进行功能检测,并在不支持该功能时显示所有内容。
if (!('onbeforematch' in HTMLElement.prototype)) {
// Expand all hidden content for unsupported browsers
document.querySelectorAll('[hidden="until-found"]').forEach((el) => {
el.removeAttribute('hidden');
// MANDATORY: also update any aria references to this element.
});
}
对于互斥的界面范式(例如内容共享同一视觉区域的自定义互斥面板),后备方案应提取所有内容,并将其线性显示在主要互动区域下方,同时使用网址锚点片段让用户能够直接导航到相应部分。