網頁功能:
容器捲動狀態查詢
總覽
只在需要時顯示「回到頂端」連結等浮動按鈕,改善使用者體驗。本指南說明如何使用 CSS container-scroll-state-queries 建構這些元素,根據容器的捲動位置設定元素樣式,而不必依賴 JavaScript 捲動事件監聽器或觀察器。
導入作業
1. 建立捲動容器
捲動容器必須宣告為捲動狀態查詢容器。
.scroller {
overflow-y: auto;
/* Establish this element as a scroll-state query container */
container-type: scroll-state;
}
2. 設定浮動元素的樣式
將元素放入容器中,並設定樣式。根據預設,這個按鈕應為隱藏狀態。
.back-to-top {
position: sticky;
bottom: 20px;
visibility: hidden;
opacity: 0;
translate: 0 20px;
transition:
visibility 0.3s,
opacity 0.3s ease,
translate 0.3s ease;
}
3. 回應捲動狀態
搭配 scroll-state 函式使用 @container 規則。如要確認使用者是否已向下捲動,請檢查容器是否可捲動至頂端。
/* When the container can be scrolled toward the top, it means the user has scrolled down */
@container scroll-state(scrollable: top) {
.back-to-top {
visibility: visible;
opacity: 1;
translate: 0 0;
}
}
備用策略
基本備用
如果系統不支援 container-scroll-state-queries,浮動元素會因預設的 visibility: hidden 而維持隱藏狀態。為確保功能正常運作,您可以選擇在不支援的瀏覽器中一律顯示元素。
/* Fallback for browsers that do not support the feature */
.back-to-top {
visibility: visible; /* Always visible */
opacity: 1;
}
/* Override for supported browsers to handle dynamic visibility */
@supports (container-type: scroll-state) {
.back-to-top {
visibility: hidden;
opacity: 0;
}
@container scroll-state(scrollable: top) {
.back-to-top {
visibility: visible;
opacity: 1;
translate: 0 0;
}
}
}
進階備用廣告 (Intersection Observer)
如需動態顯示,請使用 IntersectionObserver,在捲動器頂端的標記元素移出檢視畫面時切換類別。
<!-- Sentinel element placed at the top of the scroller -->
<div class="scroll-sentinel"></div>
/* Marker styling to ensure it does not affect layout */
.scroll-sentinel {
height: 0;
width: 0;
visibility: hidden;
}
.scrolled .back-to-top {
visibility: visible;
opacity: 1;
translate: 0 0;
}
if (!CSS.supports('container-type', 'scroll-state')) {
const sentinel = document.querySelector('.scroll-sentinel');
const scroller = document.querySelector('.scroller');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
// If the sentinel is NOT intersecting, it means the user has scrolled down
if (!entry.isIntersecting) {
scroller.classList.add('scrolled');
} else {
scroller.classList.remove('scrolled');
}
});
}, { root: scroller });
observer.observe(sentinel);
}