autofocus 在 中不生效,因规范限定其仅在页面初始加载时触发;showmodal() 后需手动调用 .focus() 并监听 focusin 事件确保聚焦准确。

autofocus 在 <dialog></dialog> 中写上就生效?不生效。它只在页面初始加载时起作用,showModal() 是后续 JS 操作,浏览器根本不会重新检查内部的 autofocus 属性。
为什么 dialog 里的 autofocus 不触发聚焦
HTML 规范明确限定 autofocus 仅在文档解析阶段(即页面首次加载)生效。当 <dialog></dialog> 处于隐藏状态(display: none)时,其子元素即使带 autofocus,也会被浏览器跳过;调用 showModal() 后,焦点由浏览器自动重置到 <dialog></dialog> 自身或其第一个可聚焦子元素,而非你标记的 autofocus 元素。
这不是 bug,是标准行为。你可以验证:打开 DevTools → Elements → 点击那个带 autofocus 的按钮,看是否出现 :focus 伪类 —— 几乎总是没有。
怎么让按钮在 showModal() 后真正获得焦点
必须手动调用 .focus(),且时机和前提要卡准:
- 确保按钮已渲染、未被
disabled、父级无inert、不在display: none或visibility: hidden容器中 - 不能在
showModal()后立刻调用.focus()—— 某些浏览器(如 Firefox)有微小延迟,导致静默失败 - 推荐用
focusin事件监听<dialog></dialog>自身获得焦点后的首次响应:
const dialog = document.getElementById('myDialog');
const confirmBtn = dialog.querySelector('[data-action="confirm"]');
dialog.showModal();
dialog.addEventListener('focusin', function handler() {
confirmBtn.focus();
dialog.removeEventListener('focusin', handler);
}, { once: true });
比 setTimeout(() => ..., 0) 更可靠,避免竞态。
按钮必须满足可聚焦条件,否则 .focus() 静默失效
<button></button> 默认可聚焦,但以下情况会让 .focus() 无效:
-
disabled属性存在 → 移除它,或改用tabindex="-1"+ CSS 控制视觉禁用 - 按钮被包裹在
inert元素中(某些 polyfill 或框架会加)→ 检查并移除 - 按钮是
<div role="button"> 之类非原生可聚焦元素 → 改用 <code><button></button>或显式加tabindex="0" - dialog 尚未完成渲染(比如刚从 React/Vue 组件挂载)→ 确保 DOM 已就绪再调用
无障碍与实际体验的关键细节
自动聚焦不只是“方便鼠标用户”,而是屏幕阅读器操作流的起点。若没正确聚焦,用户按 Tab 可能从页面其他位置开始导航,跳过 dialog 内容,甚至误触背景按钮关闭弹窗。
务必同步设置:dialog.setAttribute('aria-modal', 'true'),并用 aria-labelledby 关联标题(如 <h3 id="dlg-title">确认删除</h3> + <dialog aria-labelledby="dlg-title"></dialog>)。否则 VoiceOver 等工具可能无法识别 dialog 边界,导致焦点管理彻底失控。
最后提醒:Safari 15.4+ 才支持 showModal(),iOS 16.4+ 才稳定;旧版本需降级为 position: fixed + aria-modal="true" 的 div 模拟,且那套方案里 autofocus 同样不生效,依然得手动 .focus()。











