inert必须加在主内容容器(如<main>)而非<body>上,JS需用.inert=true/false赋值,不可用setAttribute;弹窗须与inert区域同级,旧浏览器需手动兜底aria-hidden、tabIndex和焦点劫持。

inert 不是一键开关,它只在你精准控制 DOM 结构和 JS 赋值方式时才真正“锁死”——用错地方或写法不对,就等于没加。
给谁加 inert 才有效?
必须加在**主内容容器**上,比如 <main id="main-content"> 或 <div id="page-content">,而不是 <body>。
常见错误是图省事直接 document.body.inert = true,结果弹窗、toast、loading 遮罩全失活:
• <dialog> 无法获得焦点,.focus() 失败
• toast 关闭按钮点不动,Tab 键跳不过去
• 屏幕阅读器完全感知不到弹窗存在,违反 WCAG
JS 怎么开关才不是摆设?
inert 是布尔属性,浏览器只认 .inert = true/false,其他写法全部无效:
✅ 正确:document.getElementById('main-content').inert = isModalOpen
❌ 无效:el.setAttribute('inert', '')、el.toggleAttribute('inert')、el.inert = 'true'
注意:SSR 框架(如 Next、Astro)中,服务端输出的 HTML 必须初始带 inert 属性,否则 hydration 会报 “prop mismatch”
遮罩层和弹窗必须放在 inert 区域外
这是最容易被忽略的结构前提:
• <main inert>...</main> 和 <dialog>...</dialog> 必须是同级节点,都挂载在 <body> 下
• 如果弹窗是通过 Vue/React 动态渲染进 <main> 内部,哪怕加了 inert,它也会被一并冻结
• 遮罩层(overlay)也一样:不能塞在 inert 容器里,必须提级到 <body> 底部
旧浏览器兜底不是可选,而是必做
Chrome 111+、Firefox 121+、Safari 18.0+ 原生支持;Safari 17.x、旧 Edge、部分安卓 WebView 完全不识别 inert,且 polyfill(如 @webcomponents/inert)无法模拟焦点退出和可访问性树移除:
• 检测支持:'inert' in HTMLElement.prototype
• 不支持时至少三件事同步做:
– element.setAttribute('aria-hidden', 'true')
– element.tabIndex = -1
– 递归遍历所有可聚焦子元素(button、a[href]、input、[tabindex]),逐个设 tabIndex = -1 并监听 focusin 强制重定向焦点
• 别只靠 pointer-events: none —— 它挡不住 Tab 进入、Enter 触发 click、或 JS 主动调用 .focus()
立即学习“前端免费学习笔记(深入)”;



















