【CSS】JS不要でピタッと固定!position: sticky;で作る見出し追従

Webサイトを作っていると、「スクロールしても特定の要素を画面内に残しておきたい(追従させたい)」という場面がよくあります。 昔からよく使われているのは position: fixed; ですが、最近のコーディングでは position: sticky; が大活躍しています!

「両方とも画面に固定するプロパティでしょ?何が違うの?」と疑問に思う方も多いはず。 今回は、よく使われる「セクション見出しの追従」のデモを通して、sticky の便利な動きと、fixed との決定的な違いを解説します!

デモ動作

See the Pen position: sticky; と fixed の違い by mikanbako (@mikanbako) on CodePen.

全画面でのデモ動作は以下のリンクからご確認下さい!(別タブで開かれます)

実装コード紹介

【HTML】

<div class="l-wrap">
  <h2>position: sticky; デモ</h2>
  <p class="p-desc">下にスクロールしてみてください。<br>各エリアの見出しが上部にピタッとくっつきます!</p>
  
  <div class="p-demo-box">
    
    <!-- エリア1 -->
    <section class="p-section">
      <h3 class="c-sticky-header">エリア 1 の見出し</h3>
      <div class="p-section__content">
        <p>エリア1に入りました!</p>
        <p>見出し1が固定されます。</p>
        <p>まだまだスクロールしてね!</p>
      </div>
    </section>

    <!-- エリア2 -->
    <section class="p-section p-section--bg2">
      <h3 class="c-sticky-header">エリア 2 の見出し</h3>
      <div class="p-section__content">
        <p>エリア2に入りました!</p>
        <p>見出し1が押し出されて、見出し2が固定されます。</p>
      </div>
    </section>

    <!-- エリア3 -->
    <section class="p-section p-section--bg3">
      <h3 class="c-sticky-header">エリア 3 の見出し</h3>
      <div class="p-section__content">
        <p>エリア3に入りました!</p>
        <p>見出し3が固定されます。</p>
        <p>JSを使わなくても、CSSだけでこんな動きが作れます。</p>
      </div>
    </section>

    <div class="c-spacer">スクロール用スペース</div>

  </div>
</div>

<!-- fixed の例:トップへ戻るボタン -->
<button class="c-to-top js-to-top">Top</button>

【CSS】

/* ベース装飾 */
.l-wrap {
  padding: 40px 20px;
  max-width: 600px;
  margin: 0 auto;
  color: #3e3e3e;
}

h2 {
  margin-bottom: 16px;
  font-size: 16px;
  color: #1bb4d4;
  text-align: center;
}

.p-desc {
  margin-bottom: 40px;
  font-size: 16px;
  font-weight: bold;
  color: #666;
  text-align: center;
  line-height: 1.6;
}

/* スクロール用スペース */
.c-spacer {
  height: 66vh;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #888;
}

/* セクションの装飾(スクロールできるように高さを出す) */
.p-section {
  margin-bottom: 20px;
  background: #fff;
  border: 2px solid #333;
  border-radius: 8px;
}

.p-section--bg2 {
  border-color: #e83e8c;
}

.p-section--bg3 {
  border-color: #28a745;
}

.p-section__content {
  min-height: 400px; /* スクロールさせるための高さ */
  padding: 40px 20px;
  font-size: 16px;
  line-height: 1.6;
}

/* =========================================
   💡 stickyの指定
========================================= */
.c-sticky-header {
  position: sticky; /* これを指定するだけ! */
  top: 0; /* 画面の上端(0px)に来たら固定する */
  z-index: 10; /* テキストの上に重なるようにする */
  padding: 15px;

  /* 見出しの装飾 */
  margin: 0;
  font-size: 18px;
  color: #fff;
  background: #333;
}

.p-section--bg2 .c-sticky-header {
  background: #e83e8c;
}

.p-section--bg3 .c-sticky-header {
  background: #28a745;
}

/* =========================================
   💡 fixedの指定(トップへ戻るボタン)
========================================= */
.c-to-top {
  position: fixed; /* 画面に対して完全に固定! */
  bottom: 20px;    /* 下から20pxの位置 */
  right: 20px;     /* 右から20pxの位置 */
  
  /* ボタンの装飾 */
  display: flex;
  justify-content: center;
  align-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: #1bb4d4;
  color: #fff;
  font-size: 12px;
  font-weight: bold;
  cursor: pointer;
  box-shadow: 0 4px 10px rgba(0,0,0,0.2);
  z-index: 100;
}
.c-to-top:hover {
  opacity: 0.8;
}

【JavaScript】

/* =========================================
   トップへ戻るボタンのスムーススクロール
========================================= */
const toTopBtn = document.querySelector('.js-to-top');

toTopBtn.addEventListener('click', () => {
  window.scrollTo({
    top: 0,
    behavior: 'smooth' // スムーススクロールさせる
  });
});

コードの解説と fixed との違い

sticky と fixed の決定的な違いは「親要素」!

/* =========================================
   💡 stickyの指定
========================================= */
.c-sticky-header {
  position: sticky; /* これを指定するだけ! */
  top: 0; /* 画面の上端(0px)に来たら固定する */
  ...

デモをスクロールしてみてどうでしたか?見出しが画面上部に固定された後、次のセクションが来ると、古い見出しが上に押し出されて消えていったと思います。 これが、sticky の最大の特徴です!

❌ position: fixed; の場合
画面(ブラウザのウィンドウ)に対して完全に固定されます。
親要素の枠組みを完全に無視するため、ページの最後までずっとついてきます。
(※常に表示しておきたいグローバルナビゲーションや、画面右下のトップへ戻るボタンなどに適しています)

⭕️ position: sticky; の場合
「親要素の中でのみ」固定されます!
普段は普通の要素のように振る舞いますが、スクロールして指定した位置(top: 0 など)に到達すると画面に固定されます。そして、親要素の終わりが来ると、そこで追従をやめて一緒にスクロールされて消えていきます。

sticky を使う時の注意点

sticky が効かない!という時によくある原因が、

  • 親要素(または先祖要素)に overflow: hidden; がかかっている
  • top: 0; などの位置設定がされていない

というパターンです。もし動かない時は、親要素のCSS設定を確認してみてください!

補足:公式ドキュメント

・MDN: position

まとめ

今回は position: sticky; の便利な使い方と、fixed との違いについて解説しました。

  • position: fixed; は、画面全体に対して常に要素を固定したい時(トップへ戻るボタンや、固定ヘッダーなど)に使います。
  • position: sticky; は、特定の親要素(セクションなど)の範囲内でのみ、スクロールに追従させたい時に使います。

昔はJavaScriptを使って複雑な計算をしないと実装できなかった「見出しの追従」が、今では sticky を使えばCSSたった数行で実装できてしまいます! ページ全体のパフォーマンス向上にも繋がるため、適材適所で使い分けて、モダンで快適なWebサイトを作っていきましょう!

Prev
Next