position:fixedが基準にするのは本来ビューポート
position:fixed を指定した要素は、本来ビューポート(画面表示領域)を基準に配置されます。top:0; left:0 と書けば画面の左上に張り付き、スクロールしても位置が変わらないのが期待される動きです。
ところが実際には「スクロールに付いてきてしまう」「親要素の中で止まってしまう」といったずれが起きることがあります。fixed の挙動を理解するには、まず基準が誰になっているかを疑うのが近道です。
祖先のtransformがfixedの基準を奪う
fixed が画面基準にならなくなる代表的な原因が、祖先要素に付いた transform です。transform に none 以外の値が指定された要素があると、その要素が fixed の新しい基準(包含ブロック)になり、ビューポート基準ではなくなります。
同様の効果は filter、perspective、will-change、contain などでも起こります。アニメーション用に親へ transform: translateZ(0) を入れていたり、ホバー演出で scale を当てていたりするケースは見落としがちです。
つまり「fixed 要素を直す」のではなく「fixed 要素の上にいる祖先のどれかが基準を奪っていないか」を探すのが正しい方向です。
症状別チェック表
position:fixedの要素がずれるは、症状を分けずに直そうとすると原因探しが長引きます。まず「自分だけで起きるのか」「全員で起きるのか」「特定ブラウザだけか」「差し替え後だけか」を切り分けます。
確認順序を固定すると、相対パス、ファイル名、キャッシュ、認証、外部読み込みのどこで止まっているかが見えます。修正後はローカル確認だけで終わらせず、実際の共有URLで再表示して、相手と同じ条件で直ったことを確認します。
- 自分だけ表示されない: キャッシュ、ログイン状態、ブラウザ拡張、端末幅を確認する
- 全員で表示されない: ファイル構成、相対パス、大文字小文字、アップロード漏れを見る
- 一部だけ崩れる: CSS/画像/JSごとに読み込みエラーを分ける
- 差し替え後だけ古い: URL、キャッシュ、更新対象ファイルの取り違えを確認する
原因を切り分ける手順
やみくもに CSS を書き換える前に、開発者ツールで祖先をたどり、基準を奪っている要素を特定します。
- ブラウザの開発者ツールで、ずれている fixed 要素を選択する。
- Elements パネルで親方向へ一つずつたどり、各祖先の Computed/Styles を確認する。
- transform、filter、perspective、will-change、contain のいずれかが none 以外になっている祖先を探す。
- 見つかった祖先のそのプロパティを一時的に無効化し、fixed が画面基準に戻るか確かめる。
- 戻ったら、その祖先こそが原因。プロパティを外すか、fixed 要素の配置設計を見直す。
見つかったあとの直し方
原因の祖先が判明したら、まずその transform などが本当に必要かを検討します。レイアウト目的で安易に付けたものなら、margin や別の方法に置き換えて外せることが多いです。
演出のために transform を残したい場合は、fixed 要素をその祖先の外側へ移動させる、つまり DOM 構造上で固定したい要素を body 直下などへ出すのが確実です。HTML の入れ子を見直すだけで解決することもあります。
どうしても構造を変えられないときは、position:sticky で代替できないかも検討してください。sticky は近い見た目を別の仕組みで実現でき、祖先 transform の影響を受けにくい場面があります。
直したレイアウトを関係者にすぐ確認してもらう
fixed のずれは環境やスクロール位置によって見え方が変わるため、口頭の説明より実物を見てもらうほうが早く伝わります。修正版の HTML を実際に触ってもらい、追従が直ったかをその場で確認するのが確実です。
ギガサイト便なら、作った HTML をトップページにドロップするだけで 〇〇.giga-site.com 形式の共有 URL が発行され、相手はリンクを開くだけで実機スクロールを試せます。同じ URL のままファイルを差し替えられるので、微調整のたびにリンクを送り直す必要がありません。
外部に見せたくない確認用ページは、URL のみ・パスワード・メール認証・会社ドメイン認証から認証方式を選べます。公開期限を設定すれば、確認が終わった古い URL が残り続けることも防げます。
よくある質問
position:fixedなのにスクロールで一緒に動いてしまうのはなぜですか。
祖先要素に transform や filter、will-change などが指定されていると、その要素が fixed の基準になり、ビューポート基準でなくなるためです。開発者ツールで祖先をたどり、none 以外の値を持つ要素を探してください。
transformを外せない場合はどうすればよいですか。
固定したい要素を、その transform を持つ祖先の外側、たとえば body 直下へ DOM 上で移動させると基準がビューポートに戻ります。あるいは position:sticky での代替も検討してください。
原因の祖先を素早く見つけるコツはありますか。
fixed 要素を選択した状態で、開発者ツールの Computed で祖先を一つずつ確認し、transform・filter・perspective・will-change・contain のいずれかが none 以外の要素を探すのが近道です。
stickyとfixedはどう使い分ければよいですか。
常に画面に張り付けたいなら fixed、スクロールである位置まで来たら貼り付けたいなら sticky が向きます。祖先 transform の影響を避けたいときに sticky が選択肢になります。
原因が分からないときはどこから確認すべきですか?
まず自分だけの問題か全員の問題かを分けます。次にシークレットウィンドウ、別ブラウザ、スマホで確認し、ファイル構成・相対パス・キャッシュ・認証設定を順に見ます。