position: sticky; が効かない3つの原因と対処法【CSS初心者にもわかりやすく解説】
- #CSS
- #HTML
- #Tips
position: sticky;が効かない!というときはこちらの記事をご覧ください。CSSのposition: sticky;はとても便利なプロパティですが、ちょっとしたポイントを押さえていないと効かないことがよくあります。
この記事では、stickyの基本から、うまく効かない原因とその対処法までをわかりやすく解説します。サンプルページ付きなので、実際の挙動も見ながら確認できますよ。
目次
position: sticky;とはどんなものか?
stickyはその名のとおりsticker(ステッカー)のように、要素を指定した位置へ「くっつける」ことのできる値です。
sticky以外のpositionプロパティの値
CSSのpositionプロパティでよく使われる値は以下の5つです。
static(初期値) | 通常の配置。位置指定はできない |
relative(相対位置) | 通常の配置を基準として、top・leftなどで位置指定ができる |
absolute(絶対位置) | 特定の親要素を基準として位置指定ができる |
fixed(固定位置) | 画面を基準として決まった位置に固定できる |
sticky | スクロールで指定した位置にくると固定される |
stickyはabsoluteとfixedを合わせたような、ハイブリッドな動きをするのが特徴です。
position: sticky;の使いどころ
position: sticky;はその特徴から、例えば追従ヘッダや固定サイドバー、また最近一般的になりつつあるパララックス風の動きなどによく使われます。
このWebサイトでもヘッダとサイドバーにposition: sticky;を使っています。が!実は実装するのにかなり苦労しました…
そこでここからはposition: sticky;がうまくきかない時のチェックポイントを、実際のデモページを見ながら確認していきます。
サンプルページの解説
実物を見るのが何より早い!ということで追従ヘッダと固定サイドバーのあるサンプルページをつくりました。
See the Pen Scroll-Responsive Header & Sticky Sidebar by Aizawa Web Design (@AizawaWebDesign) on CodePen.
サンプルページには以下の動きを付けました。
- ヘッダ:スクロールするとコンパクトになる
- ナビゲーションバー:スクロールすると画面上部に固定される(追従)
- サイドバー:同じく画面右側で固定されて表示
ではこのページをもとにして、stickyをきちんと機能させるためのポイントを見ていきましょう!
ポイント①stickyアイテムに位置の指定があるかどうか
以下はサンプルページのヘッダ部分のHTML構造です。
<header class="site-header" id="header">
<div class="site-title">My Demo Site</div>
<nav class="nav">
<ul>
<li><a href="#">ホーム</a></li>
<li><a href="#">サービス</a></li>
<li><a href="#">お問い合わせ</a></li>
</ul>
</nav>
</header>HTMLヘッダの中にサイトタイトルとナビゲーションメニューが入っています。続いてCSS側です。
body {
font-family: sans-serif;
line-height: 1.6;
}
.site-header {
position: sticky;
top: 0;
left: 0;
width: 100%;
z-index: 100;
background: #333;
color: #fff;
transition: all 0.3s ease;
}CSSヘッダ全体にposition: sticky;が指定されています。position: sticky;の書かれた要素をstickyアイテム、その親要素をstickyコンテナと呼びます。
ということはこの例だと
- stickyコンテナ→
body - stickyアイテム→
header(.site-header)
ということになりますね。
ここで本題のチェックポイントです。stickyアイテムをstickyコンテナ内のどの位置で固定したいか、位置の指定がないとstickyはうまく動きません。
サンプルではtopとleftを使っていますが、そのほかにbottomやrightを使った指定も可能です。とにかく何らかの位置指定を忘れないようにしてください。
チェックポイント②stickyコンテナに十分な高さがあるかどうか
stickyアイテムはstickyコンテナの範囲内でしか固定できません!つまり、stickyコンテナに十分な高さがないと、そもそもstickyの動きが発生する余地がなくなってしまいます。
サイドバーの部分でこのことを検証してみます。
<div class="container">
<main>
<h2>メインコンテンツ</h2>
<p>スクロールでヘッダーが縮小されます。トップに戻すと元に戻ります。</p>
<p>高さの確保のためにheight: 2400pxが指定されています。</p>
</main>
<aside class="sidebar">
<h3>サイドバー</h3>
<p>スクロールしても右に固定されます。</p>
</aside>
</div>HTMLページの中身はmainとasideに分かれています。
.container {
display: flex;
max-width: 1000px;
margin: 2rem auto;
gap: 2rem;
padding: 0 1rem;
transition: all 0.3s ease;
}
main {
flex: 3;
height: 2400px;
}
aside {
flex: 1;
position: sticky;
top: 7rem;
align-self: flex-start;
background: #f2f2f2;
padding: 1rem;
border: 1px solid #ccc;
}CSSCSSではdisplay: flex;を使ってaside部分をサイドバーとして画面右側に配置しています。また、main部分に強制的に高さを出すため、height: 2400px;を入れています。
asideがstickyアイテム、その親要素である.containerがstickyコンテナですね。
この時の構造は次の画像のように、stickyアイテムの高さに対してstickyコンテナが十分な高さを持っている(スクロールする余地がある)状態です。

一方、例えばasideのalign-self: flex-start;を消すと、下図のようにasideと.containerの高さが同じになってしまいます。

こうなってしまうとサイドバー部分の動く余地がないので、stickyの動きは起こらなくなってしまうんですね。
もしposition: sticky;がうまくきかないときは、画像のように適宜背景色などを付けるなどして、stickyコンテナの高さが十分にあるかどうかを確認してみてください。
チェックポイント③stickyコンテナにoverflow: visible;以外の値が指定されていないかどうか
例えばstickyコンテナにoverflow: hidden;やoverflow: auto;などが指定されていると、スクロールしてもstickyアイテムが期待どおりにくっつかないことがあります。
ちなみにoverflowプロパティのデフォルト値はvisibleです。そのため、特段overflowの指定をしていなければこのチェックポイントは問題ないはず…実際私もoverflowの値が原因でstickyがきかなかった経験はほとんどしたことがありません。
ただし、stickyコンテナ(親要素)だけでなく先祖要素の設定が影響している場合もあるため、チェックポイント①②に問題がなかったときは、stickyコンテナ、それでも問題なければ念のため先祖要素のoverflowプロパティの値を調べてみてくださいね。
ヘッダの高さが変わったときの調整
冒頭にご紹介のとおり、サンプルページではスクロールするとヘッダがコンパクトになる動きを付けました。
position: sticky;を使った追従ヘッダの実装自体はHTMLとCSSだけでできるのですが、ヘッダの高さを変えるあたりはJavaScriptの力を借りました。
スクロールすると変化するヘッダの実装方法はこちらの記事で解説しているので、ぜひ併せてご覧ください!
まとめ
position: sticky;は正しく使えば、スクロールに応じた固定表示をスマートに実現できる強力なCSS機能です。
うまく効かないときには、この記事で紹介した位置指定の有無・親要素の高さ・overflowの設定」などをまずチェックしてみてください。