スクロールしても画面上部に貼り付いて動かないヘッダーや、記事に追従する目次。こうした「ついてくる」表現を、JavaScript なしで実現できるのが CSS の position: sticky です。この記事では、sticky の基本的な使い方と、よくある「効かない」原因、便利な使いどころを、実際に動くデモつきで解説します。
目次
position: sticky とは
position: sticky は、普段は通常の位置にあり、スクロールして指定した位置に達すると、そこで固定されるという性質を持つ値です。relative(通常配置)と fixed(画面に固定)の“いいとこ取り”のような動きをします。
fixed は常に画面に固定されますが、sticky はスクロール位置が条件に達するまでは普通に流れ、達したときだけ固定される点が違います。
基本の使い方
使い方はシンプルで、固定したい要素に position: sticky と、固定する位置を表す top(または bottom / left / right)を指定するだけです。
.sticky-header {
position: sticky; /* スクロールしても追従する */
top: 0; /* 上端に達したら固定する */
}
top の指定は必須です。top: 0 なら画面の上端に、top: 20px なら上から 20px の位置に固定されます。この値を忘れると sticky は機能しないので注意しましょう。
動きを確認してみよう
下のデモで実際の動きを確認できます。プレビュー内を下にスクロールすると、ヘッダーが上部に貼り付いたままになります。CSS の position や top の値を書き換えて、動きの違いも試してみてください。
<header class="sticky-header">追従するヘッダー(スクロールしてみてください)</header>
<main class="content">
<p>セクション 1:このエリアを下にスクロールしてみてください。</p>
<p>セクション 2:ヘッダーが上部に貼り付いたままになります。</p>
<p>セクション 3:これが position: sticky の動きです。</p>
<p>セクション 4:通常のスクロールと違い、ヘッダーが消えません。</p>
<p>セクション 5:top の値で固定する位置を調整できます。</p>
<p>セクション 6:目次やテーブルの見出しにも使えます。</p>
<p>セクション 7:JavaScript を使わずに実装できます。</p>
<p>セクション 8:親要素に overflow があると効かないので注意。</p>
<p>セクション 9:もう少しスクロールしてみましょう。</p>
<p>セクション 10:ここまで来てもヘッダーは固定されています。</p>
</main>body {
margin: 0;
font-family: sans-serif;
color: #333;
}
.sticky-header {
position: sticky; /* スクロールしても追従する */
top: 0; /* 上端からの固定位置 */
background: #4f46e5;
color: #fff;
padding: 16px;
font-weight: bold;
}
.content p {
margin: 0;
padding: 20px 16px;
border-bottom: 1px solid #eee;
}
sticky が効かないときに確認すること
position: sticky は「指定したのに固定されない」とつまずきやすいプロパティです。うまく動かないときは、次の3つを順に確認してみてください。
top などの固定位置を指定していない
もっとも多いのが、top(や bottom / left / right)の指定漏れです。position: sticky だけでは、どの位置で固定するかが決まらないため動きません。top: 0 のように、固定したい位置を必ずセットで指定します。
親要素に overflow が指定されている
これは見落としやすい原因です。祖先要素のどこかに overflow: hidden・auto・scroll が指定されていると、その要素が新しい「スクロールの基準」になります。すると sticky はそのコンテナを基準に固定しようとし、コンテナ自体がスクロールしない場合は、固定されていないように見えてしまいます。
意図せず親に overflow が付いていないか確認しましょう。なお、はみ出しを隠す目的であれば overflow: clip を使えば sticky はそのまま動作します。clip は hidden と違ってスクロールコンテナを作らないため、sticky は外側のスクロールを基準に機能し続けます。「はみ出しは隠したいけれど sticky も効かせたい」というときに便利です。
親要素の高さが足りない
sticky な要素は、親要素の範囲内でしか固定されません。親要素の高さが中身とほぼ同じだと、少しスクロールしただけで親要素ごと画面外へ出てしまい、固定が解除されたように見えます。固定を続けたい範囲の親要素に、十分な高さがあるかも確認してみてください。
こんなときに便利
- 追従ヘッダー / ナビゲーション:スクロールしてもメニューが常に見える
- 記事の目次:サイドに目次を
stickyで固定し、読みながら移動できる - テーブルの見出し行:長い表でも見出しが上に残り、何の列か分かりやすい
まとめ
position: sticky を使えば、JavaScript なしで「ついてくる」要素を簡単に作れます。
position: stickyとtopをセットで指定する- 効かないときは「親要素の overflow」と「親要素の高さ」を確認する
- 追従ヘッダー・目次・テーブル見出しなどに活躍する
まずはヘッダーに position: sticky; top: 0; を付けるところから試して、動きを体感してみてください。