起因
许多网页中会添加一些基于页面滚动的动画效果,用来丰富交互体验,吸引用户的注意力。在过去,这些效果往往是通过 JavaScript 监听滚动事件进行控制的。例如下面的图片展示了 Vercel 仪表盘页面头部在滚动时的动画效果。
PS: 这段 GIF 是通过 Kap 软件录制的,它是我正在使用的一个开源的录屏软件。你可以录制屏幕上的指定区域,快速编辑录制内容,并且支持多种导出格式例如:GIF。如果你感兴趣,可以去它的网站了解更多,🙏感谢开源社区!
我最近发现可以不使用 JavaScript,仅仅利用 CSS 属性就可以实现类似的效果。
实现原理
这里主要借助 animation-timeline
和 animation-range
这两个属性。
animation-timeline
用于指定控制 CSS 动画进度的时间轴。可以设置以下 3 种类型的时间轴。
-
文档时间轴,表示动画会在文档首次加载到浏览器之后,随时间进行。将
animation-timeline
设置为auto
时或没有设置animation-timeline
时按照该方式进行,这就是正常情况下 CSS 动画的运行方式。 -
滚动进度时间轴,表示通过可滚动元素的滚动位置,转换成对应的百分比来控制动画的进行。它有两种指定方式,一种是提供一个控制滚动时间轴的滚动条的名字;另外一种是使用
scroll()
函数指定一个匿名的滚动条。一般情况下直接使用scroll()
即可,这表示使用距离当前元素最近的可滚动父级元素来控制动画的进行。更复杂的操作请查看相应的文档。 -
视图进度时间轴,表示根据滚动条内元素的可见性来控制动画的进行。默认情况下,该元素首次进入滚动区域的一个边缘时,动画进度为 0%,到达另一个边缘时,动画进度为 100%。
animation-range
用来设置动画在时间轴上的开始和结束位置。
请看下面这个例子,假设有如下的 HTML 结构
<div class="container">
<div class="square"></div>
<div class="placeholder"></div>
</div>
为 container
元素和 placeholder
元素添加一些高度,使得 container
元素可以滚动。
.container {
height: 500px;
overflow-y: auto;
}
.placeholder {
height: 1000px;
}
.square {
margin-top: 100px;
margin-left: 100px;
width: 100px;
height: 100px;
background-color: red;
}
然后为 square
元素添加动画效果。
.square {
animation: linear rotateAnimation both;
animation-timeline: scroll();
animation-range: 0 100px;
}
@keyframes rotateAnimation {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
上面的代码表示,当滚动条滚动从 0
到 100px
时,square
元素会根据滚动条的位置旋转一圈。这样通过这两个属性的配合,就实现了页面滚动控制动画进度啦。
这是我模仿 ios 天气应用实现的一个基于滚动动画的例子。
兼容性
目前这两个属性都属于实验阶段,它们的浏览器兼容性并不好,具体的情况可以查看 Can I use 的说明。
所以应该避免在生产环境上使用,如果需要使用,最好做好相应的处理,例如可以将动画代码嵌套在 @supports
查询语句内。
@supports (animation-timeline: scroll()) {
.square {
animation-timeline: scroll();
/* your code */
}
}