CSSのsticky positionを使いこなす|スクロール時の引っかかり問題を完全解決

C
クリオ
Web制作ディレクター / フロントエンジニア

こんにちは!

今日は「CSSのsticky positionを使いこなす」についてお話しします。
ほんま、このプロパティはめっちゃ便利やのに、意外とハマりどころが多いんですよね。

sticky positionがうまく効かない、その本当の理由

僕も最初は、position: stickyを使ったら思った通りに動かなくて、すごく混乱しました。
「あれ、スクロールしてもくっついてくれない…」って感じですね。

実は、sticky positionが機能するには、いくつかの重要な条件があるんです。
単にposition: stickyと書いて、topやleftを指定するだけではダメ。
親要素(コンテナ)の設定が大きく影響してくるんですよ。

よくある勘違いが「position: stickyを使えば、画面のどこにでも固定できる」と思ってしまうことです。
実は違くて、sticky要素は親要素の中でのみ「粘着」するんです。
親要素がスクロールアウトしたら、一緒に消えてしまいます。

そして、もう一つ重要なポイント。
親要素が暗黙的にoverflow: hiddenやoverflow: autoを持っていると、sticky positionは正しく動作しないことがあるんです。
これが現場でめっちゃよく見るバグの原因になります。

overflow属性が与える予想外の影響

ここからが、ほんまに重要な部分です。
overflowとsticky positionの関係、これを理解しないと、何日も悩むことになります。

例えば、このようなHTMLがあるとしましょう:

<div class="container">
  <header class="sticky-header">
    <h2>ナビゲーション</h2>
  </header>
  <div class="content">
    <!-- コンテンツ -->
  </div>
</div>

CSSが以下のようになっていたとします:

.container {
  overflow: auto;  /* ← この行が曲者 */
}

.sticky-header {
  position: sticky;
  top: 0;
}

このコードを書いたら、.sticky-headerは期待通りに動きません。
なぜかというと、overflowプロパティを持つ要素は「新しいスタッキング・コンテキスト」を生成するんです。
その結果、sticky positionの基準点が変わってしまって、意図した動作をしなくなります。

実は、overflow以外にもこういう影響を与えるプロパティがあるんですよ:

  • overflow: hidden、overflow: auto、overflow: scroll
  • transformプロパティ(どんな値でも)
  • filterプロパティ
  • perspectiveプロパティ
  • will-change(特定の値)

これらが親要素や祖先要素に設定されていると、sticky positionの動作が予想と違ってくるんです。
僕も実装途中に「なんで動かんねん…」って、こういった親要素の設定を見直して原因を発見したことが何度もあります。

実践的な活用例とベストプラクティス

では、どうやったらsticky positionを安全に使えるのか。
現場で実際に機能する方法をお伝えします。

まず大切なのは「親要素は明示的に構成する」ということです。
sticky要素は、その直近の親要素内でのみ粘着することを忘れずに。

例えば、商品リストのカテゴリーヘッダーを固定したい場合:

<div class="product-list">
  <div class="category-section">
    <h3 class="category-header">電子機器</h3>
    <ul class="products">
      <li>商品1</li>
      <li>商品2</li>
    </ul>
  </div>
  <div class="category-section">
    <h3 class="category-header">衣類</h3>
    <ul class="products">
      <li>商品3</li>
    </ul>
  </div>
</div>

CSSはこんな感じで:

.product-list {
  /* overflow は設定しない */
}

.category-section {
  /* 親要素として機能するが、overflow は避ける */
}

.category-header {
  position: sticky;
  top: 0;
  background: white;
  z-index: 10;  /* 他の要素より上に表示 */
  padding: 10px;
}

このアプローチだと、各カテゴリーセクション内でヘッダーが粘着します。
セクションがスクロールアウトしたら、ヘッダーも一緒に消える。
それで新しいセクションのヘッダーが現れる、という自然な動きになるんです。

もし「ページ全体でずっと見えるヘッダーが欲しい」ってなったら、素直にposition: fixedを使った方が、実装としてはシンプルになります。

あと、大事なのはz-indexの設定ですね。
sticky要素が他の要素に隠れてしまう場合があるので、適切にz-indexを設定しましょう。
僕の現場ではz-index: 10とかz-index: 100とか、それなりに高い値を入れてることが多いです。

そして、background色も忘れずに。
背景がないと、sticky要素の下のコンテンツが透けて見えて、読みにくくなっちゃいます。

まとめ

position: stickyは本当に便利なプロパティなんですが、使う前に「この要素の親は何か」をしっかり確認することが大事です。
特にoverflowやtransformが親要素に設定されていないか、チェックしてくださいね。

覚えておくポイント: