position stickyが効かない原因と直し方を徹底解説

position: stickyを設定したのに、スクロールしても要素が固定されない。フロントエンドに携わってきた中で、これは本当によく相談される「あるある」の一つです。
実は、stickyが効かない原因は数パターンに絞られます。そのパターンさえ知っていれば、DevToolsを開いて数分でほとんどの問題は解決できます。個人的な経験では、原因の8割以上は「親要素のoverflow」か「高さの問題」のどちらかに集約されます。
この記事では、原因を網羅的に整理したうえで、実際のチェック手順とレイアウト別の対処法までまとめてお伝えします。
この記事で学べること
- stickyが効かない原因の大半は親要素のoverflowと高さ不足に集約される
- top・bottomなどの位置指定がないとstickyは絶対に動かない
- DevToolsで祖先要素を順にたどれば数分で原因を特定できる
- flexやtableなど環境ごとのハマりポイントと具体的な直し方
- stickyが正しく機能するための3つの必須条件
position stickyが効くための3つの必須条件
position: stickyは、少し特殊な仕組みで動いています。まずは正しく動くための基本条件を押さえましょう。
そもそもstickyとは、通常の位置に配置されつつ、スクロールで特定の位置に達すると固定されるという、relativeとfixedの中間のような挙動をとるプロパティです。
この動作が成立するには、次の3つがすべて揃っている必要があります。
stickyが機能するための必須条件
逆に言えば、この3つのどれかが欠けていると、stickyは沈黙します。それでは、原因をひとつずつ見ていきましょう。
最も多い原因は位置指定と親要素のoverflow

top や bottom を指定し忘れている
position: stickyだけを書いて安心してしまう。これが初心者に最も多いミスです。
stickyは「どこで固定するか」を指定しないと動きません。ヘッダーを上部に固定したいなら、必ずtop: 0;のような位置指定が必要です。
.header {
position: sticky;
top: 0; /* これが無いと効かない */
}
親要素のoverflowがstickyを無効化している
そして、最大の落とし穴がこれです。祖先要素のどこかにoverflow: hiddenやoverflow: autoがあると、stickyはその要素を基準にしてしまい、期待通り動かなくなります。
特に厄介なのは、overflow: hiddenが「横スクロールを消すため」など、まったく別の目的で設定されているケースです。自分では気づきにくいため、DevToolsで祖先要素を一つずつ確認する必要があります。
親要素に十分な高さがない
stickyは、親要素の範囲内でしか固定されません。親の高さが子要素とほぼ同じだと、スクロールする余地がなく、固定される前に親の終端に到達してしまいます。
2カラムレイアウトのサイドバーが固定されないときは、たいていこれが原因です。親要素にコンテンツ分の高さがあるかを確認してみてください。
効かないときのデバッグ手順

原因は複数ありますが、確認する順番を決めておくと効率的です。私は次の流れで必ずチェックしています。
位置指定を確認
DevToolsでtopやbottomが指定されているか確認します。
祖先のoverflowを確認
親要素を上へたどり、overflow指定がないか順番に見ていきます。
親の高さを確認
親要素にスクロールできる十分な高さがあるか確認します。
この3ステップで、体感的にはほとんどのケースが解決します。原因別の発生頻度をざっくり整理すると、次のようなイメージです。
効かない原因の傾向イメージ
※筆者の実務経験に基づく傾向で、正確な統計値ではありません
レイアウト別の効かないケースと対処法

flexレイアウトで効かないとき
flexの子要素にstickyを付けると、親のalign-itemsによって高さが引き伸ばされ、固定される余地が消えることがあります。align-self: flex-startを子要素に付けると、本来の高さに戻り、正しくスクロールに追従します。
flexそのものの挙動に不安がある場合は、flex-basisの仕組みを理解しておくと、こうした高さの問題がぐっと見通しやすくなります。
tableのヘッダーや行が固定されないとき
古いブラウザでは、theadやtrへのstickyが効きにくい傾向がありました。現在の主要ブラウザでは、thやtdのセル自体にstickyを指定するのが確実です。
thead th {
position: sticky;
top: 0;
background: #fff; /* 背景色は必須 */
}
テーブルヘッダーは背景色を指定しないと、スクロールした本文が透けて見えてしまう点にも注意してください。
bodyやhtmlのoverflow設定が原因のとき
スムーススクロールなどの目的でhtmlやbodyにoverflowを指定していると、ページ全体でstickyが効かなくなることがあります。この場合はスクロールコンテナが分裂しているため、設定を見直す必要があります。
効くパターン
- top等の位置指定がある
- 祖先にoverflow指定がない
- 親に十分な高さがある
効かないパターン
- 位置指定を書き忘れている
- 親にoverflow: hiddenがある
- 親の高さが子と同じ
よくある質問
position stickyとfixedはどう違うのですか
fixedは常にビューポートに対して固定されますが、stickyは親要素の範囲内でのみ固定されます。スクロールに応じて「途中から固定される」動きが必要ならsticky、常に画面に貼り付けたいならfixedが適しています。
top: 0を指定しても効きません。なぜですか
位置指定があっても、祖先要素のoverflowや親の高さ不足が原因で効かないことが多いです。DevToolsで親要素を上へたどり、overflow指定と高さを順に確認してみてください。
IEでは使えますか
Internet Explorerはstickyに非対応です。現在は主要ブラウザで広くサポートされていますが、IE対応が必要な場合はJavaScriptによる代替実装を検討する必要があります。
stickyの背景が透けてしまいます
stickyで固定した要素に背景色を指定していないと、下のコンテンツが透けて見えます。backgroundを明示的に指定することで解決します。テーブルヘッダーでは特に忘れやすいポイントです。
overflowを消せない場合はどうすればいいですか
そのoverflowが不要なら削除するのが最善です。どうしても必要な場合は、stickyを適用する要素をoverflow指定のある要素の外側に移動させるか、レイアウト構造そのものを見直すことになります。
まとめ
position: stickyが効かないときは、まず「位置指定」「親のoverflow」「親の高さ」の3つを疑ってください。この順番でDevToolsを使えば、大半の問題は短時間で解決できます。
stickyは仕組みさえ理解すれば、サイドバーやヘッダー固定に非常に便利なプロパティです。うまく動かないときこそ、原因を一つずつ切り分ける練習の機会だと捉えて、落ち着いて向き合ってみてください。