本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!
欢迎关注我的公众号:前端侦探
「庆余年2」 马上就要开播了~最近起点读书APP内上架了庆余年典藏书,最大的特色是里面新加入了全新的阅读皮肤,一个拟物化的卷轴滚动效果,效果如下
就是在拖动页面时,卷轴会随着页面的滚动而展开或卷起,就像在拖动真的画布一样,非常舒适,录屏可能看着不是很清晰,强烈建议去端内自行体验。
当时看到这个效果时就在思考,如何在 web
中也实现这样一个效果呢?🤔
经过一番琢磨,发现仅使用 CSS
就能完成这样的效果。下面是我复刻的效果
这是如何实现呢?一起看看吧
一、CSS卷轴滚动的原理
首先 CSS
中并没有真正的 3d
滚动,立方体还可以勉强拼接,这种圆形的不行,因此我们需要用其他方式来实现。
这里其实是一个最简单的平移动画,只需要将纹理上下无缝平移,结合渐变和阴影,就能得到看似滚动的效果了。
先简单布局一下
1 | html复制代码<div class="reel"> |
这里要用到卷轴的素材图片,是这样的
两边保留,中间拉伸的一个自适应结构,可以用到border-image
,划分出需要拉伸的地方即可
有关border-image
的详细教程可以自行搜索,这里就不展开了,具体实现如下
1 | css复制代码.reel{ |
这样就能得到卷轴的结构了
接下来就是纹理了,素材是这个
我们把这个素材放在卷轴容器了,做上下无限平移动画
1 | css复制代码.reel-bg{ |
效果如下
现在看着非常扁平,没有立体感,主要是纹理没有融入到背景之中。
如何将纹理完美的融合到后面的背景呢?没错,需要用到混合模式,这里用正片叠底就行了
1 | css复制代码.reel-bg{ |
效果就好很多了
最后给卷轴加点阴影,超出隐藏
1 | css复制代码.reel{ |
这样就比较真实了
滚动效果出来了,如何和页面滚动关联起来呢?接着往下看
二、CSS滚动驱动动画
又是滚动,又是动画,自然会想到 CSS 滚动驱动动画,有关滚动驱动动画之前出过一篇比较详细的教程,这里就不详细介绍了,有兴趣回顾之前这篇文章
回到这里,先把整个布局完善一下
1 | html复制代码<body> |
简单修饰一下,由于卷轴要固定到顶部,可以采用sticky
布局
1 | css复制代码html{ |
效果如下
不过这里还有点问题,由于是整个页面在滚动,内容滚到顶部会漏出来,如下
所以还需要找个东西遮挡一下,这里我们直接用伪元素实现,设置相同的背景色就行了
1 | css复制代码html::before{ |
由于是sticky
,也不用关注层级问题,效果如下
现在就让卷轴滚动和页面滚动联动起来, 非常简单,只需要添加animation-timeline
属性就行了,设置滚动时间线为root
,如下
1 | css复制代码.reel-bg{ |
这样在页面滚动时卷轴也跟着“转动”了
但看着卷轴转地是不是有点慢了?
确实是这样,这个时候表示页面从头滚到到底部,执行一次动画,也就是滚动一圈,所以页面内容越多,滚动距离越长,那么卷轴转的也就越慢。
下面来修复这个问题
三、优化卷轴滚动速度
简单来处理,可以给个合适的动画次数,比如
1 | css复制代码.reel-bg{ |
这样表示页面从头滚到到底部,会执行5次动画,也就是相当于会滚动5圈,所以看着速度就变快了
现在就舒服多了。
不过这种处理方式有个问题,动画次数是跟内容长度强相关的,如果在向下滚动时动态加载内容,就需要更新这个值,稍显麻烦。
那么,有没有办法让滚动速度保持均衡呢?也就是无论内容多少,速度都是一致的。
这就需要用到 CSS
动画范围区间了,也就是animation-range
,简单来讲就是设置滚动区间。
默认情况下,滚动区间就是从页面顶部滚动到底部,我们可以手动改变这个范围,比如我们设置一个比较大的值
1 | css复制代码.reel-bg{ |
这个表示页面滚动从0
滚动到999999px
时,上面的卷轴会滚动一圈。这显然不行,我们需要动态去计算滚动的圈数,就是动画播放次数
1 | css复制代码.reel-bg{ |
为啥是这个值呢?简单解释一下,184
是这个卷轴上下的平移距离,然后再除以圆周率3.14
,这样看着会更加自然。
这样就能完美实现卷轴滚动了,无论内容长短,滚动速度都是一致的
核心实现其实就这几行,是不是非常简单
1 | css复制代码.reel-bg{ |
四、不支持浏览器兼容
虽然 CSS
实现很简单,但是兼容性还不行,截至目前(2024年4月27日)仅支持Chrome 115+
所以实际生成中不能直接使用,需要降级处理
简单的降级是不支持的不执行动画,这个只需要用@supports
查询一下就行了
1 | css复制代码@supports (animation-timeline: scroll()) { |
这样在不支持的浏览器,比如 Safari
下就不会自动播放动画了
如果也想实现卷轴滚动效果,那就需要借助JS
的力量,其实实现也不难,就是找到页面的scrollTop
和纹理的上下平移关系,做个映射就好了,具体实现如下
1 | js复制代码if (!CSS.supports('animation-timeline: scroll()')){ |
下面是在Safari
中的效果,也能完美支持了
你也可以访问以下链接查看真实效果
也可扫码体验
五、总结一下
以上就是本文的全部内容了,一个有趣的交互效果,你学到了吗,下面总结一下本文重点
- CSS卷轴滚动的原理其实是一个最简单的平移动画,只需要将纹理上下无缝平移,结合渐变和阴影,就能得到看似滚动的效果了
- 简单的平移动画看着非常扁平,没有立体感,主要是纹理没有融入到背景之中。
- 利用混合模式正片叠底,可以让平移动画看着像滚动动画了
- CSS 滚动驱动动画可以让页面滚动和卷轴滚动联动起来
- 默认情况下,页面从头滚到到底部,执行一次动画,也就是滚动一圈,所以页面内容越多,滚动距离越长,卷轴转的也就越慢
- 可以通过改变动画重复次数来调整卷轴滚动速度,局限是需要根据页面滚动长度来计算合适的数值
- 用足够大的
CSS
动画范围区间(animation-range
)配合动画重复次数可以实现卷轴滚动速度保持均衡 - 目前兼容性还有些差,可以用
CSS.supports
做兼容处理
关注我,学习更多有趣的前端交互小技巧。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发 ❤❤❤
欢迎关注我的公众号:前端侦探
本文转载自: 掘金