iPhone Safariでfixedフッターが
キーボードに隠れる原因と直し方

はじめに

チャットUIや入力フォームで、画面下に常時表示する送信ボタン付きの入力バーを position: fixed で作った。PCではどのタイミングでも下端に張り付いて見える。でもiPhoneで入力欄をタップしてキーボードを開き、その状態のままページをスクロールすると、入力バーが本来の位置から浮いたようにズレて表示されたり、画面の途中で止まったりする。

これも実装ミスではなく、iOS Safariがキーボード表示中のスクロールでposition: fixed要素をどう扱うかに起因する問題です。原因と、固定配置に依存しない対策をまとめます。

何が起きているか

iOS Safariはソフトキーボードが開いたとき、ページ全体のサイズ(レイアウトビューポート)はそのままで、実際に見えている範囲(ビジュアルビューポート)だけがキーボードの高さ分縮みます。キーボードを開いただけで操作しなければ、fixed要素は見た目上はキーボードの直上に正しく表示されます。

問題はその状態でページをスクロールしたときに起きます。本来position: fixedはスクロールしても画面内の同じ位置に留まり続けるはずの仕組みですが、キーボード表示中はビジュアルビューポートとレイアウトビューポートの基準がずれているため、スクロール中に固定要素の位置計算が一時的に狂い、入力バーが本来の位置から浮いたように見えたり、スクロールを止めた場所によって表示位置がずれたりします。

.input-bar {
  position: fixed;
  bottom: 0; /* キーボード表示中にページをスクロールすると位置がズレる */
}

なぜPCのブラウザで気づかないのか

PCにはソフトキーボードがありません。物理キーボードで入力してもビューポートのサイズは変わらないため、position: fixed は常に意図した通りに動きます。Chrome DevToolsのモバイルシミュレーターも、キーボード表示によるビューポートの縮小までは再現しません。

この問題は実機のiPhoneで、かつキーボードを開いた状態でページをスクロールしないと確認できません。キーボードを開くだけのテストでは再現せず見落とされがちです。チャットの履歴を遡ったり長いフォームをスクロールしたりする画面ほど、実際にユーザーがこの操作をする場面が多く影響が大きくなります。

この挙動は記事内では再現できません

キーボード表示中のスクロールによるズレは、記事内の小さい枠では再現できません。お手元のiPhoneで以下のリンクを開いて確認してください。

崩れる例 position: fixed で開く キーボード表示中にスクロールすると、入力バーがズレる状態を確認できます。 修正例 flex + sticky で開く 固定配置に頼らず、入力バーの位置が安定する構成を確認できます。

各ページの下にある入力欄をタップしてキーボードを表示し、その状態のままページを上下にスクロールしてください。「崩れるパターン」は入力バーが本来の位置から浮いたようにズレて表示されます。

修正方法:fixedをやめてflexレイアウトに変更する

画面全体を display: flex; flex-direction: column のコンテナにし、本文を flex: 1; overflow-y: auto のスクロール領域、入力バーをその下に続く通常のflex子要素として配置します。固定配置をやめ、レイアウトの一部として扱うのがポイントです。

.screen {
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.content {
  flex: 1;
  overflow-y: auto; /* 本文だけがスクロールする */
}

.input-bar {
  flex-shrink: 0;
  position: sticky; /* fixedではなくstickyに留める */
  bottom: 0;
}

この構成なら、入力バーは本文のスクロールコンテナに対してstickyで留められた、ページ全体とは独立した要素になります。fixedのようにレイアウトビューポート全体を基準にした位置計算をしないため、キーボード表示中にスクロールしても位置がずれません。

position: stickyを使う理由

入力バーには position: fixed ではなく position: sticky を使います。sticky はページ全体ではなく、その要素が属するスクロールコンテナを基準に位置を決めます。スクロールしてもコンテナ内での相対位置がずれないため、fixedで起きていたスクロール中の位置のブレが発生しません。

fixedのまま直す方法としてwindow.visualViewportresizeイベントでキーボードの高さを取得し、JSで都度位置を補正するやり方もありますが、スクロール中のブレまで完全に抑えるのは難しく実装も複雑になります。レイアウトをflex化してstickyに任せる方が、対応コードが少なく安定します。

まとめ

iPhone Safariはキーボード表示時、ページ全体のサイズ(レイアウトビューポート)を変えずに見えている範囲(ビジュアルビューポート)だけを縮めます。キーボードを開いただけならposition: fixed要素は正しい位置に見えますが、その状態でページをスクロールすると位置計算がずれ、入力バーが浮いたようにズレて表示されます。

対策は、固定配置に依存せずflexで画面を本文とフッターに分け、本文側だけをスクロールさせ、フッターにはposition: stickyを使うことです。チャット入力欄や検索バーなど、キーボードを開いたままスクロールする場面が多い画面を作るときは、固定フッターを使う前に一度実機のiPhoneで「開いたままスクロール」を試しておくと安心です。

関連するUI事例

キーボードを使う画面でこの問題が起きやすい代表的なUI事例です。