スクロール時にヘッダーを縮小する

スクロール時にヘッダーを縮小するパターンは、ユーザーが下にスクロールすると、ページ上部の固定ヘッダー要素がスムーズに縮小する一般的な UI パターンです。この効果は、重要なナビゲーション要素やブランディング要素にアクセスできるようにしながら、メイン コンテンツの画面領域を最大化するためによく使用されます。CSS のスクロールドリブン アニメーションを使用すると、アニメーションをドキュメントのスクロール位置にリンクすることで、この効果を宣言的かつパフォーマンスの高い方法で実現できます。

導入方法

スクロール時に縮小するヘッダーを作成する方法は次のとおりです。

  1. 固定ヘッダーを作成する: ページの上部に固定され、高さが事前に定義されているヘッダー要素から始めます。

    <header>HEADER</header>
    
    header {
      position: fixed;
      height: 200px;
      top: 0;
      left: 0;
      right: 0;
    }
    
  2. 縮小アニメーションを定義する: ヘッダーの高さを変更する CSS アニメーションを作成します。

    @keyframes shrink {
      to {
        height: 50px;
      }
    }
    
  3. アニメーションとスクロール タイムラインを適用する: アニメーションをヘッダーに適用し、scroll() 関数を使用してドキュメントのスクロール位置にリンクします。

    header {
      animation: shrink auto linear both;
      animation-timeline: scroll(block root);
    }
    
  4. animation-range を設定する: animation-range プロパティを使用して、アニメーションを発生させるスクロール距離を指定します。たとえば、スクロールの最初の 150 ピクセルでヘッダーを縮小するには、animation-range: 0px 150px; を使用します。

    header {
      animation-range: 0px 150px;
    }
    

ヒント: ヘッダーの後に続くコンテンツがヘッダーによって隠れないようにするには、ヘッダーの初期の高さと同じ padding-top を body(またはメイン コンテンツ コンテナ)に追加します。

ヒント: ページの内容がヘッダーの縮小と同期してスクロールされるようにするには、animation-range-end を開始サイズと終了サイズの差に設定します。これにより、ヘッダーが最終サイズに達したときにアニメーションが正確に完了します。このデモでは、ヘッダーが 200px から 50px に縮小されるため、animation-range-end は 150px に設定されています。

コード例

@keyframes shrink {
  to {
    height: 50px;
  }
}

header {
  animation: shrink auto linear both;
  animation-timeline: scroll(block root);
  animation-range: 0px 150px;
}

ベスト プラクティス

スクロール駆動型アニメーションを使用する場合は、スムーズでアクセスしやすいエクスペリエンスを実現するために、いくつかのベスト プラクティスに従うことが重要です。

  • 推奨: 機能検出を含める。すべてのブラウザがスクロールドリブン アニメーションをサポートしているわけではありません。@supports ((animation-timeline: scroll()) and (animation-range: 0% 100%)) を使用してサポートを確認し、サポートしていないブラウザに代替を提供します。
    • 部分的にしかサポートしていないブラウザを除外するには、ここに (animation-range: 0% 100%) チェックを含める必要があります。
    • フォールバック戦略に scroll-timeline-polyfill パッケージを使用しないでください。このパッケージは機能が完全ではなく、既知の問題が多数あります。
    • アニメーションが装飾的なものにすぎない場合は、プログレッシブ エンハンスメントを選択し、代替手段を提供しないでください。
  • 推奨事項: ユーザーの設定を尊重します。ウェブ上でのモーションを好まないユーザーもいます。prefers-reduced-motion メディアクエリを使用して、これらのユーザーに対してアニメーションを無効にするか、アニメーションを減らします。
  • 推奨: パフォーマンスの高い CSS プロパティのみをアニメーション化する。アニメーションを最もスムーズにするには、ブラウザのコンポジタ スレッドで処理できるプロパティ(transform や opacity など)のみをアニメーション化します。width や height などの他のプロパティをアニメーション化すると、パフォーマンスの問題が発生する可能性があります。
  • 推奨: 正しい宣言順序を使用する。animation 略式プロパティを使用する場合は、略式プロパティがタイムラインをリセットしないように、animation-timeline と animation-range をその後に宣言します。

scroll() 関数を使用してスクロール駆動型アニメーションを作成する場合:

  • 省略可 スクロールを明示的に指定する: 最も近い祖先スクロールをターゲットにしない場合は、scroll(root) または scroll(self) で使用するスクロールを明示的に指定します。
    • root、nearest、self では不十分な場合は、名前付きの scroll-timeline を使用します。
  • 任意: トラッキングする軸を明示的に指定します。デフォルトの block 軸をターゲットにしない場合(水平スクローラーなど)、scroll(block) または scroll(inline) でトラッキングする軸を明示的に指定します。

このユースケースに特有の点として、

  • animation-range でパーセンテージを使用する場合、アニメーション化する要素は position: static または position: relative であってはなりません。
    • これは、これらの要素が「インフロー」と見なされるためです。スクロール時にこれらの要素を縮小すると、合計スクロール距離が縮小され、スクロールへの 10% などの計算値に影響します。

ブラウザのサポートとフォールバック戦略

そのため、通常はフォールバック戦略が必要です。

スクロール駆動型アニメーションをサポートしていないブラウザでは、フォールバックを使用して視覚効果を再現できます。フォールバックは通常、スクロール リスナー(ScrollTimeline 効果の場合)または IntersectionObserver API(ViewTimeline 効果の場合)を使用して構築されます。

スクロールドリブン アニメーションのサポートが組み込まれているブラウザでは、常にネイティブ CSS 実装を使用してください。その方がパフォーマンスが向上します。

フォールバック アプローチを使用してすべてのエフェクトを再現できるわけではありません。

このユースケースでは、次のスクリプトで、スクロール駆動アニメーションをサポートしていないブラウザにフォールバックを適用します。スクロール リスナーを使用して、150px の距離にわたってドキュメントのスクロール位置を追跡し、それに応じてヘッダーの高さを更新します。

// Fallback for browsers that don't support scroll-driven animations
if (!CSS.supports('(animation-timeline: scroll()) and (animation-range: 0% 100%)')) {
  const header = document.querySelector('header');

  const initialHeight = 200;
  const finalHeight = 50;
  const scrollDistance = 150;

  window.addEventListener('scroll', () => {
    const scrollY = window.scrollY;
    const scrollPercent = Math.min(1, scrollY / scrollDistance);
    const newHeight = initialHeight - (initialHeight - finalHeight) * scrollPercent;

    header.style.height = `${newHeight}px`;
  });
}