Web 功能:
容器滚动状态查询
概览
仅在浮动按钮(例如“返回顶部”链接)有用时才显示,从而提升用户体验。本指南介绍了如何使用 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. 响应滚动状态
将 @container 规则与 scroll-state 函数搭配使用。如需检查用户是否已向下滚动,请检查容器是否可滚动到顶部。
/* 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);
}