登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  前端

HTML inert 怎样暂时禁用背景区域交互

来源:17golang原创

时间:2026-10-15 06:39:41 153浏览 收藏

我在给一个带抽屉和确认弹窗的页面整理交互时,最容易漏掉的不是弹窗本身,而是弹窗打开以后,页面背景还可以被点击、按 Tab 聚焦,甚至继续被辅助技术读到。这个场景可以先用 HTML 的 inert 解决:给背景区域设置 inert,让它和所有后代暂时退出交互;浮层关闭后移除 inert,再把焦点恢复到触发控件。

一句话概括:inert 是“区域级”的交互开关,不是只禁用一个按钮的替代品。它会影响点击、聚焦、文本选择和辅助技术访问;视觉上的遮罩、焦点回收和不支持环境的降级仍然需要开发者补齐。

先划分浮层与背景的交互边界

一个稳定的模态交互通常有两个兄弟区域:页面背景负责展示原内容,模态对话框负责当前任务。打开模态内容时,背景应该暂时不能参与交互;关闭后,背景重新可用。inert 最适合放在背景容器上,而不是随手加在 body 或单个链接上。

模态浮层、背景容器、inert 后代、焦点和辅助技术访问树之间关系的原创静态说明图
图1:结构图说明模态浮层与背景容器的交互边界,以及 inert 如何同时影响点击、聚焦和辅助技术访问。

下面这段结构把“背景”和“当前任务”分开,后面的 JavaScript 只需要切换背景容器的状态:

帮助文档

页面设置

这里的关键不是元素名字,而是边界清楚:将来页面增加导航、表单或异步提示时,只要它们仍在 main 内,就会跟随背景状态统一处理。

用 inert 暂停背景区域

inert 是布尔全局属性。它存在时,元素及其扁平树后代不能获得焦点,也不会触发普通的点击和聚焦事件;内容还会从辅助技术访问树中排除。对模态层来说,这比逐个给按钮加 disabled 更接近真正的“背景暂停”。

const pageContent = document.querySelector('#page-content');
const settingsDialog = document.querySelector('#settings-dialog');
const openButton = document.querySelector('#open-settings');

openButton.addEventListener('click', () => {
  // 先暂停背景,再打开当前任务,避免切换瞬间仍可操作页面内容。
  pageContent.inert = true;
  settingsDialog.showModal();
});

// HTMLElement.inert 与 HTML 属性 inert 表达的是同一个状态。

为了让用户能看出当前状态,还要配合遮罩或明确的视觉层级。inert 本身不会自动把背景变暗,也不会自动告诉用户为什么暂时不能操作;可见提示和真实交互状态要保持一致。

body:has(#settings-dialog[open]) #page-content {
  /* 视觉提示只表达背景暂不可操作,不代替 inert 的语义效果。 */
  opacity: 0.55;
  filter: saturate(0.7);
}

#settings-dialog::backdrop {
  /* 遮罩把当前任务和背景分开,颜色不要遮住对话框内容。 */
  background: rgb(15 23 42 / 0.42);
}

如果只是单个表单控件暂时不能使用,优先考虑 HTML 的 disabled;inert 更适合一整块内容,例如导航区、页面主体或抽屉背后的区域。

关闭浮层后怎样恢复交互

背景暂停和恢复必须成对出现。关闭对话框时移除 inert,并将焦点送回原来的打开按钮,键盘用户才不会突然失去位置。恢复动作应该挂在同一个关闭路径上,包含关闭按钮、取消动作和用户按 Esc 的情况。

HTMLElement inert 属性切换、dialog 关闭、焦点恢复和旧环境降级关系的原创静态说明图
图2:关系图展示关闭浮层后的 inert 恢复、焦点回到触发控件,以及不支持 inert 时的降级边界。
function restorePage() {
  // 先恢复背景语义,再把键盘焦点送回用户刚才触发的位置。
  pageContent.inert = false;
  openButton.focus();
}

document.querySelector('#close-settings').addEventListener('click', () => {
  // close 会结束 dialog 的模态状态,恢复动作保证背景不会一直锁住。
  settingsDialog.close();
  restorePage();
});

settingsDialog.addEventListener('cancel', (event) => {
  // cancel 对应用户按下 Esc;保留浏览器默认关闭行为后再恢复背景。
  event.preventDefault();
  settingsDialog.close();
  restorePage();
});

如果关闭后还要刷新列表或显示提交结果,建议先完成 close()、inert = false 和焦点恢复,再处理后续提示。这样即使后续请求失败,页面也不会因为等待请求而保持“背景锁死”。

可访问性上要特别注意什么

我第一次使用 inert 时,以为它会顺便完成全部模态可访问性工作,后来发现它解决的是背景边界,不是完整的对话框设计。对话框仍然要有可读的名称,关闭后要有明确的焦点去向,背景状态也最好有颜色、遮罩或说明文本提示。

原生

通过 showModal() 打开时具有特殊的模态行为;它可以脱离祖先的 inert 影响,但其他普通元素不能随意“逃出”背景的 inert 状态。不要把这个例外理解成所有自定义浮层都能自动获得同样的焦点管理。

确认删除

删除后无法从当前列表恢复。

还有一个容易忽视的点:inert 没有默认的视觉表现。只设置属性、不加遮罩或状态提示,用户可能只觉得页面“突然失灵”。视觉线索不能替代语义属性,但两者应该同时存在。

旧浏览器怎样保留降级方案

MDN 当前把 inert 标记为广泛可用,但实际项目仍可能需要照顾旧设备或嵌入式 WebView。我的做法是把基础布局和关闭逻辑先写成可用版本,再用 @supports 增强;不支持时至少保留遮罩、关闭按钮和手动的焦点策略。

.modal-backdrop {
  /* 基础样式让旧环境仍能区分当前浮层和背景。 */
  position: fixed;
  inset: 0;
  background: rgb(15 23 42 / 0.42);
}

@supports (inert: true) {
  /* 支持 inert 时让语义状态负责阻止背景交互。 */
  #page-content[inert] {
    pointer-events: none;
  }
}

需要说明的是,pointer-events: none 只能覆盖鼠标或触摸命中,不能代替 inert 对焦点和辅助技术访问树的处理。旧环境如果没有 inert,应该结合移除背景中的可聚焦入口、保存并恢复焦点等策略,而不是只加一层透明遮罩。

我的结论:用 inert 管区域,用 dialog 管当前任务

如果你要实现模态框、抽屉或全屏确认层,可以把职责拆开:背景容器用 inert 暂停,

或浮层容器承载当前任务,关闭时恢复 inert 并回收焦点,视觉层用遮罩解释状态,@supports 为旧环境准备降级。

对我来说,inert 最实用的地方不是少写一个点击拦截器,而是把“这整块区域暂时不属于当前交互”表达成了原生语义。它适合区域级暂停;如果只是禁用一个输入框,仍然应该使用更具体的 disabled。

常见问题

inert 会自动显示遮罩吗?

不会。它负责交互和辅助技术边界,不提供默认的视觉效果。遮罩、透明度、提示文本和层级样式需要自行设计。

给 body 设置 inert 可以吗?

通常不建议。更稳妥的做法是把背景内容放进明确的容器,只暂停该容器;浮层和需要继续工作的全局提示不应被误伤。

inert 和 disabled 有什么区别?

disabled 主要针对单个表单控件或控件组;inert 面向一整块元素及其后代,还会影响焦点、点击和辅助技术访问树。

把背景边界、焦点恢复、视觉提示和兼容回退一起考虑,模态交互才不会只“看起来打开了”,而是真的把当前任务交给用户。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>