捲動時縮小標頭

網頁功能: 捲動驅動動畫

捲動時縮小的標頭是常見的 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;
    }
    

提示:為避免標頭遮住後續內容,請在 body (或主要內容容器) 中加入 padding-top,其值應等於標頭的初始高度。

提示:為確保頁面內容與縮小的標頭同步捲動,請將 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 不足,請使用命名的捲動時間軸。
  • 選用:明確指定要追蹤的軸:如果不是指定預設的 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`;
  });
}