inert是浏览器原生布尔属性,可彻底冻结元素及其子树的交互与可访问性;它一次性切断键盘、鼠标、触摸、拖拽、文本选择及屏幕阅读器访问,而pointer-events:none或aria-hidden无法同时阻断所有通道。

inert 是浏览器原生的布尔属性,作用是让一个元素及其所有子元素彻底退出交互与可访问性链路——不是“视觉隐藏”,也不是“事件拦截”,而是让浏览器直接“看不见”这块 DOM。
为什么 inert 能真正冻结交互,而 pointer-events: none 或 aria-hidden 不行
常见错误是用 pointer-events: none + tabindex="-1" + aria-hidden="true" 组合模拟禁用,但问题很多:
-
pointer-events: none挡不住键盘 Tab 进入、Enter触发click、JS 主动调用.focus()或.click() -
aria-hidden="true"只影响屏幕阅读器,对键盘导航和鼠标完全无效 - 三者叠加后,焦点可能卡在不可操作元素上,辅助技术报出“可聚焦但不可用”的矛盾状态
-
inert一次性切断:鼠标点击、键盘聚焦(Tab 流中断)、文本选中、拖拽、触摸、屏幕阅读器读取、甚至Ctrl+F页面内搜索都无法匹配其中内容
inert 的正确写法和 JS 控制方式
HTML 中必须写成布尔属性形式,JS 动态控制必须用属性赋值,不能靠 setAttribute:
- ✅ 正确写法:
<main inert></main>或<div inert></div> - ❌ 错误写法:
<div inert="true"></div>、<div inert="false"></div>(字符串值被忽略) - ✅ JS 开关:
element.inert = true/element.inert = false - ❌ 无效写法:
el.setAttribute('inert', '')、el.toggleAttribute('inert')、el.inert = 'true'
赋值后立即生效:当前聚焦其中的元素会失焦,事件不再冒泡,可访问性树同步移除该子树。
模态框场景下,inert 应该加给谁
加错位置会导致整个页面卡死或浮层失活:
- ❌ 不要加给
:toast、loading、全局快捷键、<dialog></dialog>全部被冻结,焦点无法进入弹窗,关闭按钮点不动 - ✅ 推荐加给语义明确的容器,如
<main id="main-content"></main>或<div id="page-content"> <li>⚠️ 弹窗、toast 等浮层必须放在该容器的 DOM 外层,否则一并被 <code>inert隔离 - ⚠️ SSR/框架渲染时,初始 HTML 必须带
inert属性,否则 React/Vue hydration 会报 “prop mismatch” - 检测方式:
if ('inert' in HTMLElement.prototype) - 不支持时至少需三步兜底:
element.setAttribute('aria-hidden', 'true')、element.tabIndex = -1、递归遍历所有可聚焦子元素(button、a[href]、input、[tabindex])设tabIndex = -1并监听focusin强制重定向焦点 - 别依赖
pointer-events: none单独撑场——它挡不住键盘行为,也拦不住 JS 主动调用
兼容性和兜底必须手动做
inert 原生支持仅限较新浏览器:Chrome 111+、Firefox 121+、Safari 18.0+;旧版 Safari、安卓 WebView、旧 Edge 完全不识别,且没有可靠 polyfill。
最容易被忽略的是:inert 不是 CSS 效果,也不是事件代理开关;它是浏览器在解析 DOM 时就决定是否挂载该子树到交互与可访问性系统里的底层机制。写错位置、用错赋值方式、忽略 SSR 同步或兼容性兜底,任一环节出问题,整个模态逻辑就失效。











