捲動進度指標是常見的使用者介面模式,可透過視覺方式呈現使用者在可捲動文件或容器中的進度。使用者捲動時,視覺元素會更新以反映其位置,清楚直觀地呈現已瀏覽和剩餘的內容。
導入方式
如要建立捲動進度指標,您需要:
- 做為進度列的元素。這個元素通常是
position: fixed或position: absolute,因此在使用者捲動時會持續顯示。 - 與捲動位置連結的動畫。
你可以透過以下方法減少警告:
- 首先,建立 HTML 元素做為進度列。您可以依喜好設定這個元素的樣式。
- 接著,在 CSS 中定義
@keyframes動畫,縮放進度列。常見的做法是將元素從scaleX(0)縮放至scaleX(1)。 - 最後,將這個動畫套用至進度列元素,並將其
animation-timeline設為捲動時間軸。這會指示瀏覽器根據最近祖系捲動器的捲動位置,驅動動畫進度。
範例程式碼
這段程式碼會使用 scroll() 函式建立的匿名捲動時間軸,在捲動時放大 #progress 元素。
@media (prefers-reduced-motion: no-preference) {
@supports ((animation-timeline: scroll())) {
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
#progress {
position: fixed;
left: 0; top: 0;
width: 100%; height: 1em;
background: red;
transform-origin: 0 50%;
animation: grow-progress auto linear;
animation-timeline: scroll();
}
}
}
由於 scroll() 函式在 DOM 中的位置,它會追蹤 block 方向上最接近的上層捲動器,在這裡是根捲動器。
<body>
<!-- MANDATORY: Purely decorative visual scroll progress bars MUST set aria-hidden="true" to remove the empty element from the assistive technology reading tree -->
<div id="progress" aria-hidden="true"></div>
</body>
這段程式碼會使用 scroll-timeline 屬性建立的具名捲動時間軸,在捲動時放大 #progress 元素。
@media (prefers-reduced-motion: no-preference) {
@supports ((animation-timeline: scroll())) {
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
:root {
scroll-timeline: --tl block;
}
#progress {
position: fixed;
left: 0; top: 0;
width: 100%; height: 1em;
background: red;
transform-origin: 0 50%;
animation: grow-progress auto linear;
animation-timeline: --tl;
}
}
}
最佳做法
使用捲動驅動動畫時,請務必遵循幾項最佳做法,確保體驗流暢且無障礙:
- 務必加入功能偵測:並非所有瀏覽器都支援捲動驅動動畫。使用
@supports (animation-timeline: scroll())檢查支援情形,並為不支援的瀏覽器提供備用方案。- 請勿使用
scroll-timeline-polyfill套件做為備用策略,因為該套件的功能不完整,且有許多已知問題。 - 如果動畫僅用於裝飾,請選擇漸進增強,且「不要」提供備用方案。
- 請勿使用
- 務必從輔助技術閱讀流程中移除純裝飾元素:將
aria-hidden="true"套用至純視覺捲動指標,確保螢幕閱讀器不會遇到空白、未命名的節點。 - 務必尊重使用者偏好:部分使用者偏好網頁上較少動態效果。使用
prefers-reduced-motion媒體查詢,為這些使用者停用或減少動畫。 - 建議只為高效能 CSS 屬性製作動畫:如要讓動畫最流暢,請只為瀏覽器合成器執行緒可處理的屬性製作動畫,例如
transform和opacity。為width或height等其他屬性建立動畫,可能會導致效能問題。 - 建議使用正確的宣告順序:使用
animation簡寫屬性時,請在該屬性「之後」宣告animation-timeline,以免簡寫重設時間軸。
使用 scroll() 函式建立捲動驅動動畫時:
- 選用:明確指定捲動器。如果不是指定最接近的上層捲動器,請使用
scroll(root)或scroll(self)明確指定要使用的捲動器。- 如果
root、nearest或self不足,請使用命名的捲動時間軸。
- 如果
- 選用:明確指定要追蹤的軸:如果不是指定預設的
block軸 (例如在水平捲軸中),請明確指定要追蹤的軸,使用scroll(block)或scroll(inline)。
使用 scroll-timeline 屬性建立捲動驅動動畫時:
- 建議使用 CSS
<dashed-ident>做為名稱。 - 選用:明確指定要追蹤的軸。如果不是指定預設的
block軸 (例如在水平捲動器中),請使用scroll-timeline-axis明確指定要追蹤的軸。 - 務必確保查詢範圍有效:如果宣告
scroll-timeline的元素不是動畫元素的平面樹狀結構祖系,請在共用祖系上使用timeline-scope,提高scroll-timeline名稱的瀏覽權限。
備用策略
如果瀏覽器不支援捲動驅動動畫,可以使用備用方案重新建立視覺效果。備用方案通常是使用捲動事件監聽器 (用於 ScrollTimeline 效果) 或 IntersectionObserver API (用於 ViewTimeline 效果) 建構。
如果瀏覽器內建支援捲動式動畫,請一律使用原生 CSS 實作,因為這類實作的效能較佳。
請注意,並非所有效果都能使用備用方法重新建立。
針對這個用途,下列指令碼會為不支援捲動驅動動畫的瀏覽器套用備用方案。它會使用捲動事件監聽器追蹤根元素的捲動位置,並據此更新進度列的 transform 屬性。
<script>
if (!CSS.supports('animation-timeline', 'scroll()')) {
const progress = document.querySelector('#progress');
window.addEventListener('scroll', () => {
const scrollable = document.documentElement.scrollHeight - window.innerHeight;
const scrolled = window.scrollY;
const progressPercentage = (scrolled / scrollable);
progress.style.transform = `scaleX(${progressPercentage})`;
});
}
</script>