导航栏下滑隐藏上滑显现,我用了八年 JS,今天 CSS 自己会判断滚动方向了——scroll-state(scrolled) 把我那个滚动事件全删了
这个需求你肯定写过:导航栏往下滑就藏起来,往上滚就让它出现。以前要监听 scroll 事件、记录上次滚动位置、算差值判断方向,一套下来大几十行 JS,还时不时在快速滚动时判断错。
Chrome 144 推出的 scroll-state(scrolled) 把这件事彻底原生化了。
原理很简单:给滚动容器加一个 container-type: scroll-state,然后用 @container 查询最后一次滚动的方向。浏览器自己记录方向,CSS 直接读。
/* 1. 父容器开启滚动状态查询 */
html {
container-type: scroll-state;
overflow-y: auto;
height: 100vh;
}
/* 2. 导航栏:向下滚时藏起来 */
nav {
position: fixed;
top: 0;
transition: transform 0.3s ease;
}
/* 3. 向下滚 50px,导航栏往上滑出 */
nav {
@container scroll-state(scrolled: bottom) {
transform: translateY(-100%);
}
}
/* 4. 往上滚一点,导航栏滑回来 */
nav {
@container scroll-state(scrolled: top) {
transform: translateY(0);
}
}
超过阈值才触发,这是关键。以前用 JS 算差值,阈值控制要自己写;现在 scrolled 支持 top / right / bottom / left 四个方向值,还可以用 x / y 的逻辑方向。
/* 阈值控制:滚动超过 50px 才触发 */
nav {
@container scroll-state(scrolled: bottom) {
transform: translateY(-100%);
}
}
/* 也可以用逻辑方向,和书写模式无关 */
nav {
@container scroll-state(scrolled: block-end) {
transform: translateY(-100%);
}
}
不只方向——四种滚动状态全包了
scrolled 只是 Chrome 144 新增的一个值。scroll-state() 这个容器查询家族从 Chrome 133 就有了,另外三个早就能用了:
stuck:元素被边缘粘住时的状态
这是 sticky 定位的 CSS 查询接口。以前想知道一个元素当前是否处于粘附状态,只能靠 JS 拿 getBoundingClientRect 算。现在直接读:
.banner {
@container scroll-state(stuck: top) {
/* 粘在顶部时的样式 */
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
}
snapped:滚动吸附完成后的状态
轮播图场景最常用。以前想知道当前显示的是哪一张,要自己维护状态;现在 CSS 自己知道:
.carousel-item {
@container scroll-state(snapped: block) {
/* 这张卡片是当前显示的那一张 */
opacity: 1;
transform: scale(1);
}
}
scrollable:内容溢出的状态
可以用来判断这个容器是否值得显示滚动条:
.panel {
@container scroll-state(scrollable: block) {
/* 有溢出内容,可以显示滚动条 */
scrollbar-gutter: auto;
}
}
浏览器兼容性:Chrome 133+ 支持 stuck / snapped / scrollable,Chrome 144 追加 scrolled。Firefox 和 Safari 还没上。生产环境用之前记得查一下 caniuse,不过用在内部工具或者移动端 Web 场景,Chrome 独占也完全没问题。
以前这套交互要 60 行 JS 才能写清楚,现在 20 行 CSS,而且逻辑全部内聚在样式文件里,不用再维护一个独立的状态管理模块。下一个项目里,这种「监听滚动方向」的需求,直接上 scroll-state() 就完事了。
评论区
登录后可评论。