HTML
この記事では、ページ表示時に入力欄へ自動でフォーカスするautofocus属性と、利用者の操作を奪わないための注意点を説明します。
この記事でわかること
autofocusがページ表示時にフォーカスを移すこと- どの入力欄に使うと自然かを判断する方法
- 読み上げやキーボード操作を妨げないための注意点
The autofocus attribute automatically places the cursor in an input field as soon as the page loads, letting users start typing right away.
<input autofocus>
autofocus 属性とは
HTML の autofocus は、ページが読み込まれた直後(厳密には DOM が完全に構築され、描画キューが落ち着いた段階)でブラウザに “このコントロールへフォーカスを当てよ” と指示するシンプルなブール属性です。フォームで最初に入力してほしい箇所へカーソルを置く、といった ユーザーの手間を 1 クリックでも減らす 目的で導入されました。
ただし「フォーカスを奪う」という行為はアクセシビリティ・ユーザー体験・セキュリティの三面で影響が大きく、使い方次第では UX を悪化させる諸刃の剣となります。
特に、ページが読み込まれた直後にフォーカスを当てると、キーボード操作を行うユーザーにとっては便利ですが、マウス操作を行うユーザーには混乱を招く可能性があります。そのため、autofocus 属性は慎重に使用する必要があります。
最小構文と即効サンプル
HTML
<form action="/search" method="get">
<input type="search" name="q" placeholder="Enter keywords" autofocus>
<button>Search</button>
</form>
ブール属性なので autofocus="autofocus" や autofocus="" と書いても同義。慣例的に短縮形を使います。
ページ内で 最初に見つかった 1 要素だけ が有効。複数指定しても最初のもの以外は無視されます。
disabled / hidden / display:none / visibility:hidden / inert などでフォーカス可能でない場合はスキップされ、次の候補も自動では選ばれません(結果として “どこにもフォーカスが当たらない” 状態になり得る点に注意)。
動作タイミングとブラウザ実装の豆知識
- DOM Ready → レンダーツリー構築完了 → Layout → Paint
- イベントループがアイドル状態になった瞬間、ブラウザは autofocus-able な要素を走査
- 条件を満たす最初の要素へ
focus()イベントをディスパッチ
Early 2020 s の仕様変更で セキュリティ警戒レベルが高いコンテキスト(例:クロスオリジン iframe)では自動フォーカスが抑制 されるようになりました。
Chrome 102+ は バックフォワードキャッシュ復元時 にあらためて autofocus を適用します。一方 Safari は復元時には走査しないため挙動差に留意。
アクセシビリティ& UX ベストプラクティス
スクリーンリーダー利用者はフォーカス移動を “ページ読み上げ中に突然飛ばされる” と感じやすい。<h1> 見出し直後に配置し、文脈をつなぐナレーションがあると混乱を抑えられます。
モバイルではソフトキーボードが即座に現れ、レイアウトが大きく押し上がるため、ユーザーが “コンテンツを一瞥” できなくなる。重要度とページタイプ(検索専用 vs. 読み物)で使い分ける。
フォームが複数あるページでは、ユーザーが入力意図を持たないエリアで勝手にフォーカスを奪わない。“明確に主目的のフォーム only” が原則。
よくある「効かない」ケースと対処
- SPA や Intersection Observer で非同期レンダリング されたコンポーネント
- 例)Vue/React でモーダルをポータルレンダー → 初回
display:none→ 後から表示 - 対処:
mounted/useEffectでel.focus()を明示呼び出し。 - Shadow DOM 内要素
autofocus自体は有効だが、シャドウ境界を跨いでフォーカスリングが隠れると UX が悪化。- ブラウザのヒストリ復元
- Chrome は OK、Safari/Firefox は無視 → 必要なら
pageshowイベントで再フォーカス。
JavaScript での代替と補完
JavaScript
// Progressive Enhancement: まず HTML の autofocus を書き、
// 動的レンダリング時のみ JS で fallback
function safeFocus(el) {
if (!el) return;
requestAnimationFrame(() => {
// 非表示判定を自前でチェック
const rect = el.getBoundingClientRect();
const visible = rect.height > 0 && rect.top >= 0 && rect.bottom <= window.innerHeight;
if (visible) el.focus({ preventScroll: true });
});
}
preventScroll:true で 即スクロールによる CLS (Cumulative Layout Shift) を回避。
複雑な UI では “初回ロード直後はスクロールさせず、ユーザー操作でスクロール時にだけフォーカス” という UX も選択肢。
セキュリティ的視点 ― フィッシング対策
autofocus は キーロガー系攻撃 で乱用されることがある(例:見えないパスワードフィールドへ自動フォーカス → 努力せずパスワードを盗む)。
ブラウザは “同一オリジン+ユーザーの信頼済みジェスチャ” かつ “フィールドが表示領域内” という条件でフォーカス制限を行うが 完全防御ではない。
CSP (Content Security Policy) の frame-ancestors を併用し、怪しい iframe 埋め込みをブロックするのが望ましい。
モダンフレームワーク連携 Tips
React
JavaScript
const SearchBox = () => {
const ref = useRef(null);
useEffect(() => {
ref.current?.focus();
}, []);
return <input ref={ref} type="search" placeholder="Search…" />;
};
SSR(Next.js 等)で autofocus を書くと Hydration ミスマッチ が起こる場合があるため、クライアント側で useEffect へ寄せるのが安全。
Vue 3
HTML
<script setup>
import { onMounted, ref } from 'vue';
const el = ref();
onMounted(() => el.value?.focus());
</script>
<template>
<input ref="el" placeholder="検索語…" />
</template>
Vue の <input autofocus> 自体は動作するが、遅延マウント時にはズレるのでディレクティブ化(v-focus)して制御粒度を上げると保守しやすい。
Angular
HTML
<input #box />
TypeScript
@ViewChild('box', { static: true }) box!: ElementRef<HTMLInputElement>;
ngAfterViewInit() { this.box.nativeElement.focus(); }
ルーター遷移で再描画される際、Resolver でデータ待ちする場合は ngAfterViewInit 内でタイマーを挿む とチラツキが軽減。
ブラウザ互換性メモ
- デスクトップ
- Chrome 4+, Firefox 4+, Safari 5+, Edge Legacy 12+ → ほぼ網羅
- モバイル
- iOS Safari・Android Chrome ともに早期からサポート
- IE11
- 動作するが
autofocus時にscrollIntoView()相当の挙動。古いレイアウトで “画面最下部へジャンプ” ケースがあるため、条件付きクラスで回避推奨。
テスト自動化の観点
- E2E ツールでフォーカスを検証
-
- Cypress
cy.focused().should('have.attr', 'name', 'q')- Playwright
await expect(page.locator('[name=q]')).toBeFocused();
- ビジュアルリグレッション
- フォーカスリングの有無が差分になりやすい。初回キャプチャ時点でフォーカス除去用の
:focus-visibleスタイルを整備しておくと false positive を減らせる。
上級者向け Q&A スナップショット
- Q. ページ内に 2 つの
autofocusが存在し、どちらもdisplay:noneだったら? - A. いずれもフォーカス不可 → どこにもフォーカスが当たらず、スクリーンリーダーは DOM 先頭から読み上げを続行。
- Q. SPA で仮想ページ遷移時に “ブラウザアドレスは不変” だが
autofocusを効かせたい。どう設計? - A. ライブラリ側のルーターイベント(例:Vue Router の
afterEach)で “スクリーントップ/ダイアログ開閉” を検知し、対象ノードへfocus({preventScroll:true})。:tabindex="-1"を一時付与し、キーボードタブ順を壊さない工夫を添えると自然。 - Q. フォーカス移動による CLS をゼロにするには?
- A.
position:fixedのステルスプレースホルダーを読み込み直後に表示 → 実際の UI が描画されたらfocus()→ プレースホルダーを除去。視覚的なジャンプを 0 に近づけられる(ただし実装難度高)。
まとめ
autofocus は “1 クリック削減” の即効薬 だが、アクセス環境・ユーザー意図・セキュリティの三要素を考慮したうえで “ここぞ” に限って使用する。
SPA & モバイルが当たり前の 2025 年では、JavaScript 補完が実質標準。preventScroll・タイミング調整・ヒストリ復元時の再適用までワンセットでハンドリングすると、プロダクション品質に到達する。
テスト自動化でフォーカス検証をルーチン化 し、リグレッションの温床を潰すのが上級者のたしなみ。