inert 属性是浏览器原生的交互与可访问性隔离机制,使元素及其子树完全不可聚焦、不可点击、不响应任何事件且不参与可访问性树;需 Chrome 104+、Firefox 107+、Safari 16.4+ 支持,JS 动态控制须用 element.inert = true/false,不可用 setAttribute;它比 aria-hidden + display: none 或 pointer-events: none + tabindex 更彻底、更语义化,能一次性切断键盘、鼠标、触摸、拖拽、文本选择等所有交互通道。

inert 属性不是“禁用模态框”,而是让整个元素及其子树对交互和辅助技术完全不可见、不可聚焦、不可点击——它比 hidden 更彻底,也比 pointer-events: none + tabindex="-1" 组合更语义化、更可靠。
为什么不能只靠 aria-hidden="true" + display: none 处理模态框外层?
常见错误是:弹窗显示时,仅给背景区域加 aria-hidden="true" 并设 display: none 或 visibility: hidden。这会导致:
- 键盘仍可 Tab 进入被“隐藏”的表单控件(
aria-hidden不影响焦点流) - 屏幕阅读器可能跳过内容,但焦点仍在 DOM 中游走,引发可访问性报错
- JS 事件监听器依然响应
click(除非显式stopPropagation) - 移动端双指缩放、长按选中文本等行为未被阻断
inert 一次性切断所有交互通道:焦点、鼠标、触摸、键盘、剪贴板、拖拽、文本选择——这才是真正“冻结”非模态区域的正确方式。
inert 的兼容性与降级策略
目前(2026年中),inert 在 Chrome 104+、Firefox 107+、Safari 16.4+ 原生支持;Edge 同 Chrome。但 Safari 16.4 之前版本(包括 iOS 16.3 及更早)不支持。
立即学习“前端免费学习笔记(深入)”;
降级必须做,且不能只靠 JS 模拟:
- 不要用
querySelectorAll('button, input, [href]').forEach(el => el.setAttribute('tabindex', '-1'))—— 容易漏掉details、summary、自定义role="button"等 - 推荐用
focusable-selector库或手动匹配完整可聚焦 selector:button, [href], input:not([type="hidden"]), select, textarea, [tabindex]:not([tabindex="-1"]) - 对不支持
inert的浏览器,需同时设置:aria-hidden="true"+tabindex="-1"(父容器)+pointer-events: none+user-select: none - 注意:CSS
inert伪类(:is([inert]))在 Safari 中仍不可靠,样式控制建议用 class 降级
模态框开启/关闭时 inert 的正确切换时机
关键不是“弹窗显示后加 inert”,而是“在模态框获得焦点前,必须已生效”。否则会出现短暂的焦点逃逸。
实操要点:
- 模态框
open动画开始前,就应将inert加到非模态区域(如<body>或主内容容器) - 不要等
modal.showModal()返回后再操作——它异步,且焦点管理由浏览器控制 - 若用自定义弹窗(非
<dialog>),务必在element.focus()前确保inert已存在 - 关闭时,先移除
inert,再触发隐藏动画;否则动画结束前焦点无法回到原位置
复杂点在于:多个嵌套模态框(比如弹窗里再打开一个确认框)需要层级化 inert 控制,不能简单 toggle 全局 body —— 此时应维护 inert 栈,每次 push/pop 对应区域。



















