You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

模态框内聚焦陷阱实现问题 - 无障碍访问

解决模态框焦点陷阱问题

你的核心问题是原方法通过修改所有外部元素tabindex的方式,没法阻止焦点跳到浏览器地址栏(地址栏属于浏览器UI,不在页面DOM范围内)。正确的做法是监听Tab键事件,在模态框内实现焦点循环,同时打开时自动聚焦第一个可聚焦元素。

以下是修复后的完整代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        .modal {
            display: none;
            position: fixed;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            width: 250px;
            padding: 20px;
            z-index: 999;
            background-color: aliceblue;
        }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
    <button class="openModal">打开模态框</button>
    <div class="modal">
        <button class="closeModal">关闭模态框</button>
        <h4>这里是文本</h4>
        <a href="/main-page">跳转到主页</a>
    </div>

    <a href="/home">首页</a>
    <a href="/about">关于我们</a>

    <script>
        // 缓存常用元素
        const $openBtn = $('.openModal');
        const $modal = $('.modal');
        const $closeBtn = $('.closeModal');

        // 获取模态框内所有可聚焦元素
        function getFocusableElements() {
            return $modal.find('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
        }

        $openBtn.on('click', function() {
            $modal.fadeIn();
            // 聚焦模态框内第一个可聚焦元素
            const focusableEls = getFocusableElements();
            if (focusableEls.length > 0) {
                focusableEls.first().focus();
            }
        });

        $closeBtn.on('click', function() {
            $modal.fadeOut();
            // 关闭后恢复焦点到打开按钮,提升可用性
            $openBtn.focus();
        });

        // 监听Tab键事件,实现焦点循环
        $modal.on('keydown', function(e) {
            const focusableEls = getFocusableElements();
            const firstEl = focusableEls.first()[0];
            const lastEl = focusableEls.last()[0];
            const isTabPressed = e.key === 'Tab';

            if (!isTabPressed) return;

            // Shift+Tab 从第一个元素往前跳时,聚焦最后一个元素
            if (e.shiftKey && document.activeElement === firstEl) {
                lastEl.focus();
                e.preventDefault();
            }
            // Tab 从最后一个元素往后跳时,聚焦第一个元素
            else if (!e.shiftKey && document.activeElement === lastEl) {
                firstEl.focus();
                e.preventDefault();
            }
        });
    </script>
</body>
</html>

关键改进点:

  • 自动聚焦:模态框打开后,直接获取内部所有可聚焦元素并聚焦第一个,无需修改外部元素的tabindex
  • 焦点循环:监听模态框内的Tab/Shift+Tab事件,当焦点到达边界时循环到另一端,同时调用e.preventDefault()阻止浏览器默认的焦点跳转行为,彻底避免焦点跳出到地址栏
  • 可用性优化:关闭模态框后将焦点恢复到打开按钮,符合无障碍设计规范
  • 性能优化:缓存常用元素,避免重复DOM查询

内容的提问来源于stack exchange,提问作者user27057925

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 05:38:21