HTML inert属性实战:不用一行JS实现区域冻结与焦点控制

2026-06-24 0 202

做前端开发的人对“模态打开后背景不能点”这个需求太熟悉了。传统做法是:给背景容器加pointer-events: none,把里面所有可聚焦元素的tabindex设为-1,再加上aria-hidden="true"让屏幕阅读器跳过。功能勉强实现,但代码很容易漏——只要背景里有一个漏网的可聚焦元素,用户就能按Tab键绕到背景上。

HTML标准在2022年正式引入的inert属性,用一个单词就把上面所有操作打包了:标记为inert的元素及其所有子元素会立即失去交互能力——鼠标点击无效、键盘聚焦跳过、辅助技术也会完全忽略它们。这篇就从三个真实场景出发,把inert的用法和搭配逻辑讲透。

一、inert属性的作用和意义

inert是一个布尔HTML属性,可以直接写在任何元素上。它的效果可以概括为三重禁止:

  • 交互禁止:元素上的点击、输入等交互事件都不会触发。但要注意,它不会改变鼠标指针样式,那个需要额外CSS处理。
  • 聚焦禁止:元素及其子元素无法通过Tab键、focus()调用或任何方式获得焦点。原本可聚焦的控件会变成不可聚焦,就像不存在一样。
  • 无障碍忽略:屏幕阅读器会完全跳过这个区域,等价于同时施加了aria-hidden="true"和阻止焦点。

一个极其简短的例子:

<div inert>
    <button onclick="alert('这个按钮点不了')">点我</button>
    <a href="/danger" rel="external nofollow" >危险链接</a>
</div>

inert存在时,按钮和链接都无法交互,也不能被Tab键聚焦。移掉inert属性,它们立刻恢复正常。整个过程不需要操作任何子元素的属性。

二、案例一:模态对话框冻结背景

假设页面上有一个模态详情弹窗,打开时应该让背景内容不可操作。传统方案需要在打开弹窗时遍历所有背景节点的可聚焦元素并设置tabindex="-1",关闭时恢复。inert的做法是直接把背景包在一个容器里,打开弹窗时给它加上inert

2.1 HTML结构

<main id="app-content">
    <h1>页面标题</h1>
    <button>普通操作</button>
    <a href="/somewhere" rel="external nofollow" >跳转链接</a>
</main>

<dialog id="modal">
    <h2>模态内容</h2>
    <p>这里是可以交互的区域</p>
    <button id="close-modal">关闭</button>
</dialog>

2.2 交互脚本

const appContent = document.getElementById('app-content');
const modal = document.getElementById('modal');

function openModal() {
    appContent.setAttribute('inert', '');  // 背景区域冻结
    modal.showModal();
}

function closeModal() {
    modal.close();
    appContent.removeAttribute('inert');  // 恢复
}

document.getElementById('open-modal-btn').addEventListener('click', openModal);
document.getElementById('close-modal').addEventListener('click', closeModal);

// 点击遮罩关闭(ESC已有默认行为)
modal.addEventListener('click', (e) => {
    if (e.target === modal) closeModal();
});

打开弹窗后,即使用户按Tab键,焦点也只会在对话框内部循环(showModal()自动处理了焦点陷阱),背景区域完全被无视。而且屏幕阅读器也只会朗读对话框的内容,不会跑到背景里去。关闭时去掉inert,页面恢复如初。

三、案例二:表单提交时保护区域

另一个典型场景是表单提交中。为了防止重复提交或中途修改,通常会在表单上盖一层半透明遮罩并禁用所有控件。以往需要给每个inputbuttondisabled,或者阻止事件冒泡。inert提供了一个更干净的方式:把整个表单区域标记为inert

<form id="checkout-form">
    <label>姓名:<input name="name"></label>
    <label>地址:<input name="address"></label>
    <button type="submit">提交订单</button>
</form>
const form = document.getElementById('checkout-form');

form.addEventListener('submit', async (e) => {
    e.preventDefault();
    form.setAttribute('inert', '');

    try {
        await submitOrder(); // 提交逻辑
        showSuccess();
    } catch (err) {
        showError();
    } finally {
        form.removeAttribute('inert');
    }
});

表单提交期间,所有输入框和按钮都无法操作,但不需要手动管理每个控件的disabled状态。而且CSS可以为form[inert]添加遮罩样式(比如一个半透明覆盖层),从视觉上同时给出反馈。注意:inert本身不改变外观,因此视觉提示需要额外处理,通常通过CSS选择器[inert]配合伪元素完成。

四、案例三:多级菜单的非激活层级

如果一个导航菜单包含多级,只有当前展开的那一级应该是可交互的,其他层级的菜单项虽然可见但不能被操作。过去为了达到这个效果,往往要在每一级菜单上动态切换tabindexpointer-events。改用inert后,只需要在非激活的<ul>上添加属性。

<nav>
    <ul>
        <li>首页</li>
        <li>
            产品
            <ul inert>
                <li><a href="/phone" rel="external nofollow" >手机</a></li>
                <li><a href="/laptop" rel="external nofollow" >笔记本</a></li>
            </ul>
        </li>
        <li>关于</li>
    </ul>
</nav>

当用户将“产品”项展开时,用JavaScript移除子菜单上的inert,收起时再加回去。这样省去了对每个子链接单独控制的可访问性负担。

五、inert与现有ARIA属性的区别

很多人第一次看到inert会问:它和aria-hidden有什么不同?和disabled有什么区别?

特性 aria-hidden disabled inert
影响交互 不影响 阻止单个控件交互 阻止整个子树交互
焦点控制 不阻止聚焦 阻止聚焦 阻止聚焦
无障碍隐藏
子元素继承

aria-hidden只告诉辅助技术“别看这个”,但键盘聚焦仍然可以进去,用户按Tab键会落到一个屏幕阅读器看不见的控件上,造成困惑。disabled只对单个表单控件有效,不能批量禁用一整块区域。inert则同时解决了交互、聚焦和无障碍三方面的问题,是语义上最完备的冻结方案。

六、浏览器支持与渐进增强

inert属性在主流通用浏览器中已经全面可用:

  • Chrome 102+ 和 Edge 102+
  • Firefox 112+
  • Safari 15.5+(桌面和移动端)

这意味着在2024年的今天,绝大多数用户都可以享受到原生inert的好处。对于极少数尚不支持的浏览器,可以使用一个轻量的polyfill:

// 简易polyfill:检测inert支持,不支持时手动模拟
if (!('inert' in HTMLElement.prototype)) {
    const observer = new MutationObserver((mutations) => {
        // 对新增的[inert]元素递归设置tabindex=-1并添加aria-hidden
        // 省略完整实现,实际项目中建议用官方inert-polyfill
    });
}

但通常建议直接使用,不支持的浏览器权当退化(模态背景依然可以用传统方式处理)。

七、视觉反馈的补充

inert只负责行为,不处理外观。为了让“冻结”状态对视觉用户可见,一般会配合CSS使用:

[inert] {
    opacity: 0.6;
    pointer-events: none; /* 进一步保证鼠标穿透 */
    user-select: none;
}
/* 如果是模态背景,通常还会加一个覆盖层 */

pointer-events: none在有些场景下并不是必须的,因为inert已经阻止了交互,但加上它可以防止鼠标悬停时出现文本选择或光标变化。

八、总结

inert属性的出现,标志着浏览器开始把“区域冻结”这种常见的交互模式原生化。它不再需要开发者小心翼翼地管理整棵DOM树上每个可聚焦节点的tabindex,也不用担心遗漏某个角落的aria-hidden。一行属性,三个效果——交互屏蔽、焦点管理、无障碍隐藏——全部生效。

如果你的项目里有模态弹窗、分步表单、多级菜单、或者任何需要“暂时冻结一片区域”的场景,现在就可以把inert用起来。它不像其他新API需要大量学习,就是一个属性和一种思路的转变,但能带来代码量的大幅减少和可访问性的显著提升。

HTML inert属性实战:不用一行JS实现区域冻结与焦点控制
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请联系本站我们会及时删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 html HTML inert属性实战:不用一行JS实现区域冻结与焦点控制 https://www.taomawang.com/web/html/2272.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务