inert 属性必须直接写在容器上且不带值,如 ,浏览器仅识别布尔属性本身;js 控制需用 element.inert = true/false,不可用 setattribute;动态插入节点需手动调用 inert.apply(el);模态框等浮层须与 inert 区域平级;旧浏览器需手动降级处理。

inert 属性必须直接写在容器上,不能带值
直接加 inert 就生效,比如 <main inert></main>。浏览器只认这个布尔属性本身,不接受 inert=""、inert="true" 或 inert="false" —— 后两者会被当字符串值处理,inert="false" 依然启用禁用行为。
常见错误是模板里写成:<div inert="{{isDisabled}}">,结果服务端或框架输出 <code>inert="false",实际还是锁死了区域。
- ✅ 正确写法(静态):
<div id="page-content" inert> <li>✅ 正确写法(JS 动态):<code>document.getElementById('page-content').inert = true - ❌ 错误写法:
el.setAttribute('inert', 'true')、el.toggleAttribute('inert')、el.inert = 'true' - ✅ 焦点自动退出:当前聚焦的
input会失焦,Tab 键跳过整块区域 - ✅ 事件不冒泡:子元素上的
click、keydown不会到达父级监听器 - ⚠️ 动态插入的新节点(如 Vue 组件重渲染新增的
<div inert>)不会被 polyfill 自动接管,需手动调用 <code>inert.apply(el)DOM 结构必须把浮层放在 inert 容器外层
给
或加inert是最常见且最危险的错误。它会连同<dialog></dialog>、<div class="toast">、全局 loading 遮罩一并冻结,导致关闭按钮点不了、Tab 进不去输入框、读屏器读不到弹窗内容。 <p>正确结构是让模态框与主内容区成为兄弟节点:</p> <pre class="brush:php;toolbar:false;"><div id="app"> <main id="page-content" inert></main><dialog open></dialog><div class="toast"></div> </div></pre> <ul> <li>✅ <code>page-content.inert = true只影响它自己及其子元素 - ✅
<dialog></dialog>和<toast></toast>在 DOM 中与其平级,完全不受影响 - ⚠️ 如果滚动靠
实现,而你又意外给加了inert,滚动会卡死——但inert本身不影响滚动能力
JS 控制 inert 必须用 .inert = true/false,不是 DOM 属性操作
inert 是 HTMLElement 的原生属性,不是 HTML attribute,所以 setAttribute 和 removeAttribute 完全无效。赋值后浏览器立刻退出焦点、阻断事件冒泡、从可访问性树中移除整个子树。
尤其注意 SSR/ hydration 场景:React/Vue/Astro 服务端已渲染 inert,客户端 JS 必须立即同步 element.inert = isModalOpen,否则触发 “prop mismatch” 警告。
不支持 inert 的浏览器必须手动兜底,polyfill 不可靠
Chrome 111+、Firefox 121+、Safari 18.0+ 原生支持;Safari 17.x 及更早、旧 Edge、部分安卓 WebView 完全忽略 inert,且官方 @webcomponents/inert polyfill 无法模拟焦点重定向和 AT 树移除,只能做“半禁用”。
检测后必须手写降级逻辑:
if ('inert' in HTMLElement.prototype) {
mainContent.inert = isModalOpen;
} else {
const focusables = mainContent.querySelectorAll(
'button, a[href], input:not([type="hidden"]), select, textarea, [tabindex]:not([tabindex="-1"])'
);
focusables.forEach(el => {
el.tabIndex = isModalOpen ? -1 : '';
if (isModalOpen) el.setAttribute('aria-disabled', 'true');
});
mainContent.style.pointerEvents = isModalOpen ? 'none' : '';
mainContent.setAttribute('aria-hidden', isModalOpen ? 'true' : 'false');
}
- ⚠️ 别漏掉
details、summary、[role="button"]等可聚焦元素 - ⚠️
pointer-events: none挡不住键盘,必须配合tabIndex = -1和focusin监听劫持焦点 - 真正容易被忽略的是:
inert不是样式开关,也不是事件拦截器——它是让那一块 DOM 子树在浏览器眼里“不存在于交互上下文”中











