autofocus 属性常失效,因其仅在HTML初始解析时生效且需满足多重条件:必须写在源码中、元素需首屏存在、不可隐藏或禁用、iOS Safari直接忽略;仅支持特定表单控件;可靠替代是带环境判断和聚焦检查的JS focus()。

autofocus 属性在多数桌面浏览器中能“开箱即用”,但实际项目里它大概率失效——不是你写错了,而是它根本没机会触发。
autofocus 为什么经常不生效
浏览器只在 HTML 初始解析阶段识别 autofocus,且仅对满足全部条件的元素起作用:
-
autofocus必须写在原始 HTML 源码中,el.setAttribute('autofocus', '')或input.autofocus = true完全无效 - 目标元素必须在页面首次加载时就存在于 DOM 中(Vue/React 渲染后动态挂载?失效)
- 不能是
display: none、visibility: hidden或opacity: 0状态(哪怕只是过渡动画中的一帧) - 不能带
disabled或readonly(哪怕 JS 后续才移除) - iOS Safari 直接忽略该属性,无论你怎么写
哪些元素能用 autofocus
只有原生可聚焦的表单控件支持,且类型有明确限制:
- ✅
<input type="text">、<input type="email">、<input type="search">、<input type="number"> - ✅
<textarea>、<button>、<select> - ❌
<input type="hidden">、<input type="checkbox">(虽技术上允许,但用户几乎无法感知焦点) - ❌
<div>、<span>(除非显式加tabindex="0") - ⚠️
<input type="password">在部分 Android 浏览器中会因安全策略跳过聚焦
替代方案:JS focus() 的安全写法
当 autofocus 不可靠时,.focus() 是唯一通用解法,但必须规避常见陷阱:
- 包裹
if (typeof window !== 'undefined'),避免 SSR 环境报document is not defined - 检查是否已聚焦:
if (input && document.activeElement !== input),防止覆盖用户已有操作 - 移动端 iOS 必须绑定到用户手势后(如
click、touchend),否则被静默拒绝 - SPA 路由切换场景下,不要依赖
useEffect/mounted,改用useLocation或beforeEach监听路径变化再调用 - 避免在
blur回调里立刻.focus(),可能触发循环或被浏览器拦截
移动端和 SSR 场景的硬性限制
iOS Safari 对 autofocus 的无视是平台级行为,不是 bug;服务端渲染时 DOM 不存在是确定性事实。这两点决定了:只要项目需要兼容 iOS 或采用 SSR(Next.js/Nuxt/Vite-SSR),就必须放弃纯 HTML 方案。最简健壮写法是:
if (typeof window !== 'undefined') {
const input = document.querySelector('#search-input');
if (input && document.activeElement !== input) {
input.focus();
}
}
注意:这个逻辑仍不能解决 iOS 首屏自动弹键盘问题——它只保证焦点落在输入框,软键盘是否弹出取决于用户是否刚完成一次可信任的手势。真正可控的,永远是“点击按钮 → 聚焦 → 弹键盘”这一链路,而不是“页面打开 → 自动弹键盘”。

















