1. 前言
仅使用 CSS 创建一个具有无限滚动轮播的动画 ,无需 JavaScript。首先是无限滚动轮播动画效果在我们常见的开发中都是借用 JavaScript 实现,如果纯粹使用 CSS,我觉得还是一个比较有趣的。
2. 效果预览

3. 效果分析
- 一屏展示了三个图片元素;
- 动画依次向左移动;
- 三个图片循环出现,出现无限滚动轮播效果。
4. 实现轮播卡片
- 使用 display: grid 将图片一排放三个;
- 使用 gap 设置两两图片之间的间距;
- 使用 aspect-ratio 设置图片的宽高比;
- 注意使用 taro 框架,因此需要去除图片的默认宽高。
4.1 DOM 结构
ini
<View className="rui-will-change-content">
<View className="rui-grid-content">
<Image
src={`https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/252666/12/28906/128995/67c70923F7ea34dfc/8ac042791e1dbae8.jpg!q70.dpg.webp`}
className="rui-grid-item"
></Image>
<Image
src={`https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/262472/10/27398/106649/67c551a9F4eb82724/5b9f7cd6b67b1101.jpg!q70.dpg.webp`}
className="rui-grid-item"
></Image>
<Image
src={`https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/266314/35/9312/155449/677cf57eF804de0b9/e709efdffed05aef.jpg!q70.dpg.webp`}
className="rui-grid-item"
></Image>
</View>
</View>
4.2 CSS 实现
css
.rui-grid-content {
display: grid;
width: 100%;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.rui-grid-item {
width: auto; // 去掉 taro 图片的默认宽高
height: auto;
aspect-ratio: 1;
border-radius: 24px;
}
4.3 实现效果

5. 无限循环
- 由于是无限循环,因此需要将循环部分再复制一份;
- 原理就和 js 实现无限循环时需要将最后一个元素和第一个元素分别复制到轮播前后;
- 当然我们复制的 DOM 需要跟在需要循环的元素后边,才能形成无限循环;
- 使用 display: flex 将第一组元素和复制元素放在一排;
- 使用 flex: 0 0 100%; 确保元素最少是一屏。
5.1 复制后 DOM 结构
ini
<View className="rui-will-change-content">
<View className="rui-grid-content">
<Image
src={`https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/252666/12/28906/128995/67c70923F7ea34dfc/8ac042791e1dbae8.jpg!q70.dpg.webp`}
className="rui-grid-item"
></Image>
<Image
src={`https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/262472/10/27398/106649/67c551a9F4eb82724/5b9f7cd6b67b1101.jpg!q70.dpg.webp`}
className="rui-grid-item"
></Image>
<Image
src={`https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/266314/35/9312/155449/677cf57eF804de0b9/e709efdffed05aef.jpg!q70.dpg.webp`}
className="rui-grid-item"
></Image>
</View>
<View className="rui-grid-content">
<Image
src={`https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/252666/12/28906/128995/67c70923F7ea34dfc/8ac042791e1dbae8.jpg!q70.dpg.webp`}
className="rui-grid-item"
></Image>
<Image
src={`https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/262472/10/27398/106649/67c551a9F4eb82724/5b9f7cd6b67b1101.jpg!q70.dpg.webp`}
className="rui-grid-item"
></Image>
<Image
src={`https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/266314/35/9312/155449/677cf57eF804de0b9/e709efdffed05aef.jpg!q70.dpg.webp`}
className="rui-grid-item"
></Image>
</View>
</View>
5.2 CSS 实现
css
.rui-will-change-content {
overflow: hidden;
display: flex;
}
.rui-grid-content {
flex: 0 0 100%;
display: grid;
width: 100%;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.rui-grid-item {
width: auto; // 去掉 taro 图片的默认宽高
height: auto;
aspect-ratio: 1;
border-radius: 24px;
}
5.3 不设置 flex: 0 0 100% 效果

5.4 设置 flex: 0 0 100% 效果

通过第一张效果图可以看出,原本的元素和复制的元素之间少了我们之前设置的图片间距 20px,因此需要设置盒子元素的右边距 20px。设置 flex: 0 0 100% 后,就只有第一组元素可见,复制的元素不可见。
6. 设置动画效果
由于可视元素和复制元素相连接,那么直接让两组元素进行动画。
6.1 CSS 实现
- 使用 CSS 变量,实现了动画的时间可以通过变量来控制;
- padding-right 实现了第一组元素和复制元素之间的间距;
- will-change: transform 这里是为了优化 CSS 动画,告诉浏览器循环动画切换的时候进行提前计算;就是在第一组元素和复制元素切换的时候,也就是动画执行完成的时候切换效果的卡顿没有那么明显,当然目前我肉眼是没有看出效果来的;
- 使用 animation 执行动画的循环轮播执行。
css
.rui-grid-content {
--time: 10s;
flex: 0 0 100%;
display: grid;
width: 100%;
padding-right: 20px;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
will-change: transform;
animation: scrolling var(--time) linear infinite;
}
@keyframes scrolling {
to {
transform: translateX(-100%);
}
}
6.2 最终效果

7. 实际使用示例
7.1 公告栏

7.2 trae 的人员介绍

7.3 gitee 众多知名企业及开源组织已在使用

8. 总结
8.1 本篇文章的实现方法
- 动画向左移动直到隐藏使用 transform: translateX(-100%),这里的动画是在动画结束时,第一组元素刚好全部隐藏。
- 第二组元素本来是完全隐藏,在执行 transform: translateX(-100%),动画结束时,刚好从隐藏状态全部显示出来。
8.2 实现演示

8.3 超出一屏的公告栏演示

8.4 总结
通过上边的演示动画可以看出,此处的动画原理就是第一组元素和复制的第二组元素同时执行相同的动画,位移距离相同,然后复制元素又是跟随在第一组元素后,所以在动画无限循环的时候,看着就是无限滚动的效果。
9. trae 官网的实现原理总结
由于 transform: translateX(-200%) 位移的是自身的两倍,可以看到动画时间是 200s,但是第二组元素(复制元素)需要提前一半的时间进行移动。也就是延迟时间需要设置 -100s,这样就能达到复制元素是跟随在第一组元素后,形成无限滚动的轮播。其实这种实现方法相比第一种变得复杂了一点,需要单独设置复制元素的动画延迟时间,理解也没有第一种容易。

css
@keyframes scrolling {
to {
transform: translateX(-200%);
}
}
10. gitee 登录页的实现原理总结
理解了上边两种无限滚动轮播的原理,我们思考一下还有没有更加简单的实现方法呢?其实原理都一样,怎么让动画变少,变得更加简单且容易理解呢?当然是可以的,方法就是将第一组元素和复制的第二组元素放在一个盒子里边,现在这个盒子的长度是不是就是第一组元素的两倍?并且复制的第二组元素也是跟随在第一组元素后的?现在是不是只需要移动这个父元素盒子就能达到第一组元素和复制的第二组元素一起移动的效果?虽然一起移动了,但是要实现无限滚动,也就是需要复制的第二组元素刚好显示在最左边的边界,那么移动距离就是原来的 50% 。因为父元素是第一组元素的两倍,所以移动一半,然后无限循环,就能实现无限滚动了。这个方法将需要执行动画的元素由原来的两个,减少到现在在父元素的一个,性能是不是得到了提升?
css
@keyframes scrolling {
to {
transform: translateX(-50%);
}
}
11. 总结
通过上边三种方法,可以看出实现的原理其实都是一样的,只是在实现的基础上进行优化。原理相同,实现的方法确很多,就看你怎么使用,在此基础上怎么进行优化。多思考,多实践,多看看别人的实现,相同的功能,有时灵光一闪,可能别人比你实现的更加优秀,这就是需要我们去不断的学习总结。