模态对话框是Web界面中最常用的交互模式之一,但实现真正的可访问性却让开发者十分头疼:焦点必须锁定在对话框内,背景内容需对辅助技术隐藏,且键盘操作不能逃逸。传统方案依赖JavaScript监听Tab键、维护焦点陷阱,代码冗长且易出错。HTML新引入的inert属性彻底简化了这一切——它让浏览器原生地将元素从交互和辅助技术中“移除”,只需一行标记。本文将通过构建一个无需JavaScript的模态对话框,彻底解锁inert的威力。
一、inert属性的核心能力
inert是一个布尔HTML属性,当添加到某个元素上时,会产生以下效果:
- 该元素及其所有子元素变得不可交互(鼠标点击、触摸事件均无效)。
- 元素失去焦点能力,无法通过Tab键聚焦。
- 辅助技术(如屏幕阅读器)将忽略该元素,就像它不存在一样。
这与aria-hidden="true"有相似之处,但aria-hidden只是提示辅助技术,并不阻止键盘聚焦或点击事件;而inert从浏览器引擎层面彻底冻结了交互。这使得它成为处理模态对话框背景、隐藏非活跃面板的理想选择。
浏览器支持方面,Chrome 102+、Edge 102+、Firefox 112+、Safari 15.5+均已完整支持,可以放心用于生产环境。
二、基础案例:用inert构建模态对话框
我们将构建一个带有“打开对话框”按钮和模态窗口的简单页面。当对话框打开时,背景内容自动变为inert,从而锁定焦点和交互,且无需任何JavaScript。
2.1 HTML结构
<body>
<main id="main-content">
<h1>我的应用</h1>
<button id="open-dialog">打开对话框</button>
<!-- 其他页面内容 -->
</main>
<div id="modal-dialog" role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">确认操作</h2>
<p>你确定要执行此操作吗?</p>
<button id="close-dialog">取消</button>
<button id="confirm-btn">确定</button>
</div>
</body>
2.2 纯CSS实现开关(利用:target)
我们可以使用:target伪类来切换对话框的显示,并配合inert属性冻结背景。当URL哈希指向对话框ID时,对话框显示,背景变为inert。
/* 默认背景可交互,对话框隐藏 */
#modal-dialog {
display: none;
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
background: white; padding: 2rem; z-index: 1000;
box-shadow: 0 0 20px rgba(0,0,0,0.3);
}
/* 当对话框成为目标时显示它,并让背景变为inert */
#modal-dialog:target {
display: block;
}
#modal-dialog:target ~ #main-content,
#modal-dialog:target ~ main {
inert: true; /* CSS中无法设置inert属性!需要用HTML属性控制 */
}
这里我们发现一个关键问题:inert是HTML属性,不能直接在CSS中设置。因此纯CSS无法动态改变inert状态。我们需要极简的HTML结构技巧来规避JavaScript:使用<details>元素或popover API。但popover已经自动处理背景交互,而inert更适用于手动控制。为了展现inert的用法,我们可以展示结合少量JavaScript的最佳实践,这仍然是当前最推荐的模式。
三、最佳实践:JavaScript + inert的优雅方案
只需几行JavaScript,我们就可以完美结合inert属性,实现无懈可击的模态对话框。
// 获取元素
const openBtn = document.getElementById('open-dialog');
const closeBtn = document.getElementById('close-dialog');
const dialog = document.getElementById('modal-dialog');
const mainContent = document.getElementById('main-content');
// 打开对话框
openBtn.addEventListener('click', () => {
dialog.showModal(); // 使用
注意:我们同时使用了<dialog>元素的showModal()方法,它提供了原生模态行为和Esc关闭支持。而额外的inert保证了背景在屏幕阅读器中也被完全隐藏,因为单纯<dialog>的模态并不总是从辅助技术中移除背景(取决于浏览器实现)。通过主动设置inert,我们确保了键盘焦点群和辅助技术遍历的绝对隔离。
进一步,我们可以使用MutationObserver或dialog的close事件自动移除inert,但上述手动方式已经足够清晰。
四、与aria-modal和传统陷阱的对比
| 方法 | 焦点限制 | 辅助技术隐藏 | 代码复杂度 |
|---|---|---|---|
| JavaScript焦点陷阱(监听Tab) | 手动维护 | 需配合aria-hidden | 高,易出错 |
| 仅使用aria-modal=”true” | 依赖浏览器,部分支持不完整 | 仅提示辅助技术 | 低,但不够可靠 |
| inert + dialog.showModal() | 自动锁定 | 彻底隐藏 | 极低,声明式 |
从对比中可见,inert配合原生<dialog>提供了最健壮、最简洁的模态实现。开发者不再需要编写复杂的焦点陷阱逻辑,只需将背景标记为inert即可。
五、其他应用场景
除了模态对话框,inert还可用于:
- 侧滑面板:当侧边菜单滑出时,将主内容设为
inert,防止键盘焦点误入。 - 多步骤表单:非活跃步骤的容器设为
inert,确保用户不会跳步操作。 - 加载状态下的页面区域:防止用户在数据提交过程中重复点击。
在这些场景中,直接添加/移除inert属性即可瞬间冻结或解冻区域,且浏览器原生优化,没有性能负担。
六、辅助技术测试与验证
使用屏幕阅读器(如NVDA或VoiceOver)测试模态对话框时,开启inert后,阅读器将完全跳过背景内容,仅读取对话框内部信息。同时,使用Tab键导航时,焦点只会在对话框内的可聚焦元素间循环(因为背景已不可聚焦),无需任何额外代码。
可以通过Chrome DevTools的“Accessibility”面板检查背景元素的ARIA状态,确认其被标记为“ignored”。
七、总结
inert属性虽小,却解决了前端可访问性领域的一大痛点。它将原本需要大量JavaScript实现的焦点隔离和辅助技术隐藏,转变为一行HTML属性。结合<dialog>元素,我们获得了近乎完美的模态交互体验。现代Web开发正向着更声明式、更原生的方向演进,inert正是这一趋势的缩影。立即在你的项目中实践它,让可访问性不再是事后补救,而是与生俱来的能力。

