autofocus 属性不可靠,仅对服务端初始 html 中非隐藏、可聚焦的原生表单元素可能生效;ios safari 忽略它,js 动态添加无效;应改用带条件判断和用户手势保障的 focus() 方法。

autofocus 属性不能可靠指定初始焦点位置,尤其在现代 Web 场景中它大概率不生效——这不是你写错了,而是它的设计决定了它只对静态、首屏、非隐藏的原生表单控件“可能起效”。
autofocus 只在 HTML 初始解析时生效,且条件苛刻
浏览器只在解析原始 HTML 字符串阶段识别 autofocus,之后任何 JS 动态添加(比如 el.setAttribute('autofocus', '') 或 input.autofocus = true)都无效。它要求:
- 元素必须存在于服务端返回的初始 HTML 中(SSR/Next.js/Nuxt 页面里,客户端 hydrate 后才挂载的组件不满足)
- 元素不能是
display: none、visibility: hidden、opacity: 0(哪怕只是 CSS 动画第一帧) - 不能带
disabled或readonly(哪怕 JS 紧接着就移除) - 必须是可聚焦的原生元素:
<input type="text">、<textarea></textarea>、<select></select>、<button></button>;<div autofocus> 完全无效,即使加了 <code>tabindex="0"也不行(autofocus不会激活该 div 的聚焦能力) - iOS Safari 直接忽略该属性,无论你怎么写
-
<input type="hidden" autofocus>——type="hidden"不可聚焦 -
<input type="password" autofocus>—— 部分 Android WebView 因安全策略跳过 -
<div tabindex="0" autofocus>xxx</div>——autofocus对非表单元素无作用 -
<input autofocus="">或<input autofocus="true">—— 虽然 HTML5 允许,但多余且易引发误解;正确写法只有autofocus(布尔属性,无值) - 多个
autofocus—— 浏览器通常只处理第一个,行为不一致,不应依赖 - SSR 环境下先判断:
if (typeof window !== 'undefined'),否则报document is not defined - 避免覆盖用户操作:
if (input && document.activeElement !== input) { input.focus(); } - 移动端 iOS 必须绑定到用户手势后(如
click、touchend),否则静默失败 - SPA 路由切换时,不要依赖组件挂载钩子(
useEffect/mounted),改用路由变更事件监听后再聚焦 - dialog 场景下,
showModal()后需等待 dialog 激活再聚焦,推荐用focusin事件一次监听:dialog.addEventListener('focusin', handler, { once: true }) -
autofocus不派发focus事件(旧版 Safari 除外),所以监听input.addEventListener('focus', ...)捕获不到 -
.focus()可以传选项:input.focus({ preventScroll: true })防止页面滚动,autofocus没这个能力 - 密码管理器、翻译插件、屏幕阅读器可能劫持或延迟焦点,导致行为不可预测
-
form.reset()后autofocus不恢复,必须手动补焦
哪些写法看似合法但实际无效
这些常见误用不会触发聚焦:
真正能落地的替代方案:JS focus() 的安全调用
当你要确保焦点落到某个元素上(尤其是登录页搜索框、dialog 确认按钮),必须用 JS 主动调用 .focus(),并绕过常见陷阱:
容易被忽略的焦点副作用
即使 autofocus 或 .focus() 成功,也不代表键盘弹出或 focus 事件触发:
复杂点不在怎么写,而在判断“什么时候能写”——只要项目涉及 SSR、iOS、动态渲染或无障碍要求,autofocus 就不该作为焦点逻辑的主干,而只是一个可有可无的降级提示。











