HTML inert 属性怎样让模态框外内容不可交互
来源:17golang原创
时间:2026-11-03 13:47:29 199浏览 收藏
模态框打开时,背景区域不能只靠半透明遮罩“看起来不能点”。更稳妥的做法是把背景根节点设为 inert,让它及其后代不能获得焦点、响应点击,也不会继续出现在辅助技术的交互路径中。关闭模态框时再把 HTMLElement.inert 恢复为 false。
官方资料:https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/inert
如果页面使用原生并通过showModal()打开,浏览器会让对话框外的文档内容自动处于 inert 状态;如果是自定义遮罩层,就需要自己把背景容器切换为inert。
先分清遮罩层和 inert 状态
遮罩层只负责视觉反馈,例如压暗背景、阻止鼠标落到背景上的一部分区域;它不会自动改变键盘 Tab 顺序,也不会让背景按钮从辅助技术的可访问树中消失。inert 是交互状态:元素和它的 flat tree 后代不能聚焦、不能触发点击事件,通常也不能被页面查找、选中文本或通过辅助技术操作。

因此,先把“用户看不见”与“用户不能交互”分开处理:遮罩负责颜色和层级,inert 负责交互边界,模态框自身负责焦点进入与退出。
把背景内容包成一个可切换的根节点
自定义模态框最容易维护的结构,是让正文和导航共用一个背景根节点,弹窗放在它的外层。这样只需要切换一个属性,不必逐个给按钮加 disabled。
编辑资料
这里的关键不是 role 本身,而是页面背景拥有稳定的 DOM 边界。后续 JavaScript 可以统一写入 page-shell.inert,弹窗关闭后再恢复。
用 HTMLElement.inert 切换模态框外内容
HTMLElement.inert 是布尔属性:设为 true 就等价于给元素增加 inert 状态,设为 false 则移除这个元素自身的显式 inert 状态。下面的示例还保存了打开前的焦点,关闭后把焦点还给触发按钮。
const pageShell = document.querySelector('#page-shell')
const modal = document.querySelector('#edit-modal')
const openButton = document.querySelector('#open-modal')
const closeButton = document.querySelector('#close-modal')
let lastFocusedElement = null
function openModal() {
// 记录触发控件,关闭时把键盘焦点还给它。
lastFocusedElement = document.activeElement
pageShell.inert = true
modal.hidden = false
// 等弹窗显示后再聚焦内部控件,避免 hidden 状态拦截 focus。
closeButton.focus()
}
function closeModal() {
// 先移除背景的 inert 状态,再隐藏弹窗。
pageShell.inert = false
modal.hidden = true
// 只有仍在当前文档中的元素才适合恢复焦点。
if (lastFocusedElement instanceof HTMLElement && lastFocusedElement.isConnected) {
lastFocusedElement.focus()
}
}
openButton.addEventListener('click', openModal)
closeButton.addEventListener('click', closeModal)
这段代码只解决“背景是否能交互”和“打开前焦点如何回来”两个问题。若要实现完整的焦点循环、Escape 关闭和滚动锁定,还要根据模态框组件的实际需求继续设计。
dialog.showModal() 与手动 inert 有什么区别
原生 通过 showModal() 进入模态状态时,对话框外的文档内容会自动变成 inert;这适合愿意采用原生对话框语义的页面。自定义 div 弹窗不会自动获得这个行为,必须手动切换背景容器。
const dialog = document.querySelector('#profile-dialog')
const openDialog = document.querySelector('#open-dialog')
const closeDialog = document.querySelector('#close-dialog')
openDialog.addEventListener('click', () => {
// showModal() 进入原生模态状态,外部文档会被浏览器隔离。
dialog.showModal()
})
closeDialog.addEventListener('click', () => {
// close() 退出模态状态,浏览器恢复外部文档的交互。
dialog.close()
})
要注意两个边界:第一,显式给对话框自身加 inert 会让它也不能操作;第二,父元素继承的 inert 状态不能靠子元素设置 inert = false 抵消。需要解除时,应从真正带有 inert 的祖先节点开始恢复。

给 inert 状态补上可见提示
inert 本身不会自动改变颜色或透明度。若背景内容被禁止操作却仍然看起来完全正常,用户可能不知道为什么按钮暂时不能用。可以用属性选择器补充视觉提示,但不要把视觉样式当作 inert 的替代品。
/* 只提示被 inert 的背景区域,交互限制仍由 inert 属性负责。 */
[inert] {
opacity: 0.55;
filter: saturate(0.7);
}
/* 弹窗打开时禁止背景滚动,避免视觉焦点和页面位置脱节。 */
body:has(#edit-modal:not([hidden])) {
overflow: hidden;
}
如果浏览器兼容目标不支持 :has(),可以在打开和关闭时给 body 增删一个 class。视觉提示、滚动处理和 inert 的职责要分开,便于后续更换组件。
disabled、aria-hidden 与 inert 不能互相替代
| 手段 | 主要作用 | 适用边界 |
|---|---|---|
inert | 冻结元素及后代的交互、聚焦和辅助技术访问 | 整块背景、暂时不可操作的区域 |
disabled | 禁用单个表单控件 | 按钮、输入框等控件自身不可用 |
aria-hidden | 改变辅助技术的语义可见性 | 不能单独阻止真实点击或键盘聚焦 |
| 遮罩 CSS | 表达层级、暗化背景和视觉状态 | 不能单独完成交互隔离 |
常见错误是只写 aria-hidden="true",却留下可聚焦的链接和按钮;或者只把背景盖住,却没有把键盘焦点移进弹窗。实践中通常是 inert + 明确焦点管理 + 视觉提示 组合使用。
一份收尾清单
- 自定义弹窗先保证背景有统一根节点,再切换
HTMLElement.inert。 - 打开时保存触发元素,关闭时确认它仍在文档中再恢复焦点。
- 原生
dialog.showModal()已经提供模态外部隔离,不要重复给错误的父节点加 inert。 - 不要用
aria-hidden代替真实的交互禁用,也不要用透明度代替 inert。 - 父级继承的 inert 不能由子级简单设置为 false,恢复状态时要回到实际控制节点。
一句话总结:遮罩解决“看起来被挡住”,inert 解决“确实不能交互”,而焦点管理解决“用户接下来从哪里继续操作”。把三者拆开设计,模态框的键盘和无障碍行为会更稳定。
相关问题
给一个按钮设置 inert 可以代替 disabled 吗?
不建议。单个表单控件的语义状态优先使用 disabled;inert 更适合冻结一整块内容及其后代。
inert 会自动显示灰色或半透明效果吗?
不会。它主要改变交互和可访问性状态,视觉变化要由页面自己的 CSS 明确表达。
dialog.showModal() 还需要手动给背景加 inert 吗?
正常原生模态对话框不需要再手动冻结整个文档;只有自定义弹窗、特殊嵌套结构或额外的业务区域才需要单独设计。
-
424 收藏
-
132 收藏
-
275 收藏
-
306 收藏
-
Golang · Go教程 | 2星期前 | html · 模板 · Go教程 · html/template · Go html/template HTML转义 模板安全 template.HTML 上下文自动转义281 收藏
-
124 收藏
-
109 收藏
-
166 收藏
-
文章 · 前端 | 40分钟前 | javascript · css · range CSS Custom Highlight API Highlight CSS.highlights ::highlight()118 收藏
-
441 收藏
-
410 收藏
-
486 收藏
-
344 收藏
-
文章 · 前端 | 54分钟前 | javascript · 前端开发 · 浏览器API · JavaScript sort 浅拷贝 toSorted Array.prototype.toSorted 不可变排序177 收藏
-
106 收藏
-
102 收藏
-
357 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习