直接给<main>或<div id="page-content">加inert属性可安全冻结背景,但弹窗、toast等浮层必须置于其DOM外层;JS应仅控制mainContent.inert = isModalOpen,SSR需同步hydration状态以防prop mismatch警告。

直接给 <main> 或 <div id="page-content"> 加 inert 属性,就能安全冻结背景区域——但必须把弹窗、加载蒙层等浮层放在它的 DOM 外层,否则一并被锁死。
模态框开启时只禁用主内容区,不碰 <body>
很多人误以为给 <body inert> 最省事,结果 toast、全局 loading、键盘快捷键全失效。真实 DOM 结构应类似:
<div id="app"> <main id="main-content" inert></main> <dialog open></dialog> <div class="toast"></div> </div>
JS 控制逻辑只操作 mainContent.inert = isModalOpen;<dialog> 和 <toast> 必须是 <main> 的兄弟节点,不能嵌套在它内部。
- 若用 React/Vue,SSR 渲染时输出
inert属性,hydration 后必须同步.inert = true/false,否则触发 “prop mismatch” 警告 -
<body>上设inert会阻断所有全局事件监听(如document.addEventListener('keydown', ...)),包括 ESC 关闭弹窗的逻辑 - 移动端虚拟键盘弹出/收起时,若
inert区域包含滚动容器,可能触发焦点丢失或滚动错位——此时需在virtualkeyboard事件中手动恢复焦点到安全元素
inert 在拖放(drag & drop)场景中的冻结边界
拖拽过程中要防止用户误点背景按钮或滚动列表,inert 比 pointer-events: none 更可靠:后者不拦键盘,且拖拽结束时焦点常卡在不可见元素上。
立即学习“前端免费学习笔记(深入)”;
- 拖拽开始时,对
#page-content设.inert = true;拖拽结束立即设回false - 不要对
document.body设inert,否则document.elementFromPoint()在拖拽中可能返回null,导致 drop 区域识别失败 - 若拖拽目标是 shadow DOM 内部元素,原生
inert不穿透 shadow boundary,需在 shadow root 内单独控制
旧浏览器兜底时,polyfill 不等于“完全兼容”
WICG/inert polyfill 支持 Safari 10+,但它只模拟交互禁用,不处理辅助技术语义——屏幕阅读器仍可能读取 inert 元素内容。
- 必须在所有业务 JS 执行完后、首次使用
inert前加载 polyfill:<script src="https://unpkg.com/wicg-inert@3.1.2/dist/inert.min.js"></script>放在</body>前,不用async - 动态插入的新
[inert]元素(如 Vue 组件重渲染、ReactuseState更新后挂载)polyfill 不自动接管,得手动调用inert.apply(el) - IE11 中,polyfill 无法正确处理
Element.focus()主动调用,需额外拦截并重定向焦点到document.body或安全容器
真正容易被忽略的是:inert 不影响样式和布局,所以视觉上毫无提示——你得自己加 [inert] { opacity: .7; } 或其他 CSS 来表明“已冻结”,否则用户会困惑为什么点不动。



















