【JS不要】CSSだけでスクロール状態を検知!最新機能 scroll-state() の使い方と実務で使える実装パターン

Web技術

これまで、Webサイトの実務制作において「画面をスクロールしてヘッダーが上部に固定(sticky)されたら背景色をつける」「スクロールスナップで現在表示されている要素だけを強調する」といった演出を実装する場合、JavaScript(ScrollイベントやIntersection Observer)を使うのが当たり前でした。

しかし、CSSの最新仕様(コンテナークエリー)として登場した「scroll-state()」を使えば、これらをCSSだけで完結できるようになります。

今回は、フロントエンドで今最も注目されているこの最新機能について、実務で今すぐ使える具体的なコード例と合わせて解説します。

1. scroll-state() とは?何ができるの?

scroll-state() は、CSSコンテナークエリー(Container Queries)の拡張機能です。要素の「スクロールの状態(固定されているか、スナップされているか、スクロール可能か)」をブラウザが自動で検知し、その状態に応じたスタイルをCSSだけで適用できます。

指定できる主な状態(クエリー)には以下の4つがあります。

  • stuck: position: sticky で要素が画面端に固定されている状態
  • snapped: scroll-snap-type によって要素がピタッとスナップ停止している状態
  • scrollable: 対象のエリアが上下左右にスクロール可能な状態(スクロールバーが出ているか)
  • scrolled: ユーザーがどの方向にスクロールしたかの検知(スクロール方向の判定)

実務で特に需要が高い「stuck(固定検知)」と「snapped(スナップ検知)」の実装パターンを見ていきましょう。

2. 実装パターン①:ヘッダーが固定(sticky)されたら色を変える

もっとも一般的な「スクロールしたら追従ヘッダーの見た目(背景色や文字サイズ)を変える」実装です。

HTML構造

状態を監視するための親コンテナー(コンテナー要素)の中に、固定したいヘッダーを配置します。

<div class="nav-container">
  <nav class="sticky-header">
    <h1>Global Navigation</h1>
  </nav>
</div>

CSSコード

親要素に container-type: scroll-state を指定して監視対象にし、子要素側で @container scroll-state(stuck: top) を使って固定時のスタイルを定義します。

/* 1. 親要素をスクロール状態の監視コンテナーに設定 */
.nav-container {
  container-type: scroll-state;
}

/* 2. 通常時のヘッダースタイル(上部にsticky配置) */
.sticky-header {
  position: sticky;
  top: 0;
  background-color: transparent; /* 初期は透明 */
  transition: background-color 0.3s ease;
}

/* 3. 上部(top)に固定(stuck)された瞬間に適用するスタイル */
@container scroll-state(stuck: top) {
  .sticky-header {
    background-color: #ffffff; /* 固定されたら白背景にする */
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); /* 影をつける */
  }
}

3. 実装パターン②:スクロールスナップで中央にある要素を強調する

カルーセル(スライダー)や縦スクロールの全画面演出で、現在アクティブ(ピタッと止まっている)パネルだけを大きくしたり、文字を表示したりする演出です。

HTML構造

スクロールさせる外枠のコンテナーと、その中にある各セクションを用意します。

<div class="timeline-container">
  <section class="card">Card 1</section>
  <section class="card">Card 2</section>
  <section class="card">Card 3</section>
</div>

CSSコード

親にスクロールスナップの設定と、コンテナーの設定を両方持たせることで、個々の子要素がスナップされたかを検知できます。

/* 1. スクロールスナップの親コンテナーを設定 */
.timeline-container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
  height: 400px;
  container-type: scroll-state; /* 監視コンテナー化 */
}

/* 2. 各カードの通常スタイル */
.card {
  scroll-snap-align: center;
  opacity: 0.5;
  transform: scale(0.9);
  transition: all 0.3s ease;
}

/* 3. y軸(縦方向)にスナップ(停止)した要素に適用するスタイル */
@container scroll-state(snapped: y) {
  .card {
    opacity: 1;
    transform: scale(1); /* アクティブな要素だけ拡大・強調 */
  }
}

4. 実務導入における注意点とブラウザ対応状況

この scroll-state() は非常に強力ですが、実務に投入する際は以下の点に留意する必要があります。

  • ブラウザの対応状況: 主要ブラウザ(Chromium系、Safari、Firefox)で順次実装が進んでいますが、古い環境のユーザー向けには「機能しなくてもレイアウトが崩れない(Progressive Enhancement)」設計にする必要があります。
  • JavaScriptとの使い分け: アニメーションのトリガーにするだけであればCSSで十分ですが、スクロール状況をサーバーにログ送信したり、複雑な条件分岐を行ったりする場合は、従来通りJavaScript(Intersection Observer)との併用が必要です。

まとめ:CSSによる表現力は次のステージへ

これまでは「重い」「記述が面倒」と言われがちだったスクロール連動演出ですが、scroll-state() の登場によって、コード量は圧倒的に削減され、パフォーマンスもネイティブブラウザ準拠で非常に滑らかになります。

Web制作の工数削減とパフォーマンス向上を両立できる素晴らしい機能です。モダンブラウザの普及に合わせて、ぜひ皆さんのプロジェクトでも先取りして試してみてください。

(Visited 1 times, 1 visits today)
タイトルとURLをコピーしました