inert属性不能替代css,必须配合pointer-events: none等样式提供视觉反馈;它原生禁用交互、焦点和可访问性暴露,但不改变任何css属性,仅靠inert会导致按钮仍显示为可点击而实际无效。

inert 属性本身不改变 pointer-events,必须手动加 CSS
inert 是浏览器原生的交互隔离机制,它让元素及其子树完全退出焦点流、忽略鼠标/键盘事件、从可访问性树中移除——但它 不修改任何 CSS 样式,包括 pointer-events。按钮依然显示为可点击状态,光标悬停时仍是 default 或 pointer,用户会误点、困惑、甚至以为功能失效。
所以仅写 <div inert><button>提交</button></div> 是不够的。你必须显式用 CSS 把视觉反馈补上:
-
inert容器内所有可交互元素(button、a、input等)应统一设pointer-events: none - 同时加灰阶样式,例如
opacity: 0.6或filter: grayscale(50%),否则视觉上毫无禁用感 - 避免只对容器设
pointer-events: none:它不阻止子元素上的focus()调用,也不影响键盘 Tab 进入,更不移出可访问性树——这正是inert的价值所在,不能被 CSS 替代
为什么不能只靠 pointer-events: none 模拟 inert
pointer-events: none 只拦截鼠标和触摸事件,但以下行为仍会发生:
- Tab 键仍能聚焦到
button或input,焦点卡住后无法自然离开 - 屏幕阅读器仍会读出按钮文本,报出“可聚焦但不可操作”的矛盾语义
- JS 主动调用
el.focus()不会失败,而是把焦点强行塞进去(inert下该调用静默无效) - 双指缩放、长按复制、拖拽等非鼠标交互不受影响
换句话说:pointer-events: none 是“看不见手”,而 inert 是“整块区域在浏览器眼里根本不存在”。二者目的不同,叠加使用是合理且必要的,但不能互相替代。
inert + CSS 的正确组合写法
推荐用属性选择器一次性覆盖,避免漏掉动态插入的子元素:
/* 禁用 inert 区域内所有交互元素的指针和视觉反馈 */
[inert] button,
[inert] input,
[inert] select,
[inert] textarea,
[inert] a[href],
[inert] [tabindex]:not([tabindex="-1"]) {
pointer-events: none;
opacity: 0.6;
cursor: not-allowed;
}
- 不要用
[inert] { pointer-events: none }:父容器设了之后,子元素的pointer-events: auto无法穿透生效,但更重要的是——它不解决键盘和 AT 问题,纯属多余 - 避免在 JS 中动态切换 class 来模拟禁用:class 控制不了可访问性树,也拦不住
focus(),且容易和 SSR/hydration 状态冲突 - 移动端需额外加
user-select: none防止误选文字,尤其当 inert 区域含大段文本时
浏览器兼容性决定了你必须降级处理
Chrome 111+、Firefox 121+、Safari 18.0+ 原生支持 inert;Safari 17 及更早、旧 Edge、多数安卓 WebView 完全忽略该属性。检测逻辑必须写死:
if ('inert' in HTMLElement.prototype) {
mainContent.inert = isModalOpen;
} else {
// 降级:手动禁用可聚焦元素 + aria-hidden + pointer-events
mainContent.setAttribute('aria-hidden', isModalOpen);
mainContent.style.pointerEvents = isModalOpen ? 'none' : '';
const focusables = mainContent.querySelectorAll('button, a[href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
focusables.forEach(el => {
el.tabIndex = isModalOpen ? -1 : '';
});
}
- polyfill(如
wicg-inert)只能模拟部分行为,无法修复辅助技术语义缺失,不能当作兼容性兜底的终点 - SSR 渲染时若服务端已输出
inert,客户端 hydration 后必须同步.inert = true/false,否则 React/Vue 会报 “prop mismatch” - 真正容易被忽略的是:inert 不是视觉开关,也不是事件代理层——它是 DOM 子树在浏览器渲染引擎与可访问性栈中的“存在性注销”。没这层理解,CSS 再配得准,交互逻辑照样崩。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











