こんにちは!コーダーのゆうしです。
CSSの position: sticky を使ったのに「スクロールしても固定されない」「途中で止まってしまう」という経験はありませんか? position: sticky はいくつかの条件が揃わないと動作しない少し癖のあるプロパティです。この記事では効かない原因と対処法をまとめて解説します。
position:stickyとは?
position: sticky はスクロールに応じて relative と fixed の中間のような動きをするプロパティです。通常は通常フローに従って配置されていますが、スクロールが一定位置に達すると固定表示に切り替わります。
.header {
position: sticky;
top: 0; /* 上端から0pxの位置で固定 */
}ヘッダーの追従・テーブルの見出し固定・サイドバーの追従など実務でよく使います。
position:stickyが効く条件
position: sticky が正しく動作するには以下の条件がすべて揃っている必要があります。
top/bottom/left/rightのいずれかが指定されている- 親要素・祖先要素に
overflow: hidden/overflow: auto/overflow: scrollが指定されていない - 親要素に十分な高さがある
- スクロールが発生している要素が正しい
効かない原因と対処法
① top / bottom / left / rightが指定されていない
position: sticky は固定する位置を指定しないと動きません。position: sticky だけではなく、必ず top などとセットで使ってください。
/* NG:固定位置が指定されていない */
.sticky-box {
position: sticky;
}
/* OK:topで固定位置を指定する */
.sticky-box {
position: sticky;
top: 20px; /* 上端から20pxの位置で固定 */
}② 親要素・祖先要素にoverflowが設定されている
一番よくある原因です。祖先要素のどこかに overflow: hidden / overflow: auto / overflow: scroll が指定されていると、position: sticky が正しく動作しません。
/* これがあるとstickyが効かない */
.parent {
overflow: hidden;
}対処法: 開発者ツールで親要素・祖先要素を上に向かってひとつずつ確認して、overflow の指定がないか探してください。
/* overflowをvisibleに戻す */
.parent {
overflow: visible; /* または削除する */
}ただし overflow: hidden を削除すると別のレイアウトに影響が出ることがあります。その場合は overflow: clip を試してみてください。overflow: clip ははみ出しを非表示にしつつ、stickyへの影響を与えないプロパティです。
.parent {
overflow: clip; /* overflow:hiddenの代替。stickyに影響しない */
}③ 親要素の高さが足りない
position: sticky は親要素の範囲内でしか固定されません。親要素の高さと同じかそれ以上にスクロールすると固定が解除されます。
<div class="parent"> <!-- この高さの範囲内でしか固定されない -->
<div class="sticky-box">固定したい要素</div>
<!-- コンテンツが少ないと固定範囲がほぼない -->
</div>対処法: 親要素に十分なコンテンツ量があるか確認してください。固定したい要素の親要素が短すぎると、固定される前に解除されてしまいます。
④ スクロールしている要素が違う
position: sticky はスクロールが発生している要素を基準に動作します。body や html ではなく別の要素でスクロールが発生している場合、sticky が効かないことがあります。
/* bodyではなくこの要素でスクロールしている場合 */
.scroll-container {
height: 100vh;
overflow-y: scroll;
}対処法: sticky にしたい要素がスクロールしている要素の子孫になっているか確認してください。
⑤ display:flexやgridの影響
親要素が display: flex や display: grid の場合、子要素の position: sticky が効かないことがあります。
/* flexの子要素にstickyが効かない場合がある */
.parent {
display: flex;
}
.sticky-box {
position: sticky;
top: 0;
}対処法: flexの子要素に align-self: flex-start を追加すると解決することがあります。
.sticky-box {
position: sticky;
top: 0;
align-self: flex-start; /* これを追加 */
}よく使う実装パターン
ヘッダーを画面上部に固定する
.header {
position: sticky;
top: 0;
z-index: 100;
background: #fff;
}テーブルの見出し行を固定する
thead th {
position: sticky;
top: 0;
background: #f5f5f5; /* 背景色を指定しないと透けてしまう */
z-index: 1;
}サイドバーをコンテンツに追従させる
.sidebar {
position: sticky;
top: 20px; /* ヘッダーの高さ分ずらす */
align-self: flex-start; /* 親がflexの場合に必要 */
}躓きやすいポイント
固定されているのに背景が透ける
position: sticky で固定した要素に背景色を指定していないと、コンテンツが透けて見えます。必ず background を指定してください。
.sticky-header {
position: sticky;
top: 0;
background: #ffffff; /* 背景色を必ず指定する */
}stickyヘッダーの下にコンテンツが隠れる
ページ内リンクでジャンプしたときに、stickyヘッダーの裏にコンテンツが隠れることがあります。scroll-padding-top を使うとジャンプ先の位置をヘッダー分ずらせます。
html {
scroll-padding-top: 80px; /* ヘッダーの高さ分指定する */
}overflow: clipが効かないブラウザがある
overflow: clip はIE・古いSafariでは非対応です。現在の主要ブラウザではほぼ対応していますが、古い環境へのサポートが必要な場合は注意してください。
まとめ
position: sticky が効かない原因のほとんどは 祖先要素のoverflowの設定 か topなどの固定位置の指定漏れ です。まず開発者ツールで祖先要素を上に向かってひとつずつ確認して overflow の指定を探してみてください。overflow: clip を使うことで overflow: hidden の代替としてstickyへの影響を避けることもできます。
ご不明な点やコーディングのご依頼はお問い合わせからお気軽にどうぞ。

