说起前端页面轮播效果,想必大伙都不会陌生,图文并茂的说明再加上可以定时切换的特点, 让几乎每个展示自己产品或者设计的网站都有这一模块 。传统的Web开发教学中都会讲到利用JavaScript实现轮播效果,但是有没有想过用CSS去实现它呢?实际上这是可行的,一起来看看吧。
1. 思路分析
在开始写之前,首先要理清CSS实现轮播的思路:使用animation动画定时切换样式。
所以在做这个效果之前,需要有CSS动画相关的知识,具体内容可以参考菜鸟教程上的animation动画教学。
2. 开始实现
现在,我们从最简单的效果开始 。
2.1 基础效果
最简单的实现就是定时切换区域的背景图,HTML结构写出来是这样子的:
<div class="carousel-img" style="background-image: url(test.jpg)"></div>
只要定时改变background-image
属性值就OK了,CSS样式如下:
.carousel-img{
width:130px;
height:100px;
background-repeat:no-repeat;
background-position:center center;
background-size:cover;
animation:carousel 12s linear infinite normal
}
@keyframes carousel {
0%,100%{
background-image: url(test.jpg)
}
25%{
background-image: url(test1.jpg)
}
50%{
background-image: url(test2.jpg)
}
75%{
background-image: url(test3.jpg)
}
}
demo预览效果如下:
如果你足够细心,这时候就会发现一个问题:当这个效果第一次载入的时候,第一张跟第二张图片的间隔非常短,往后切换就没有这种问题。观察Firefox浏览器的CSS动画查看器,可以发现这个动画的进度图是这样子的:

其中紫色点表示CSS规则中指定的各个时段的状态,蓝绿色的阶梯状表示动画的过程,每个阶梯的拐角位置(红色箭头位置)表示图片切换的时间点,在这张图中,拐角位置位于每两个紫色点的正中间。可以看到第一次图片切换的时候,动画才运行了12.5%,第二次切换在37.5%,第三次在62.5%,第四次在87.5%,然后再下一个周期的12.5%处再次切换。
CSS动画与JavaScript动画的区别在于,使用@keyframes
声明的animation动画,我们指定的是一个状态,即动画运行到50%的时候应该处于一个什么状态,而在50%之前,动画就开始执行状态切换。但是JavaScript的动画,我们指定的是切换的时间,代码运行到这一行时才会执行切换这个命令,新的状态会在执行命令之后才能生效。
为了尽可能避免这种问题,可以在第一次切换点25%之前再加一句状态声明:20%{background-image: url(test.jpg)}
,这样在动画20%的时候还是维持着第一张图片的状态,也就是人为地让状态切换时间延后。
修改刚才的@keyframes
代码段:
@keyframes carousel{
0%,20%,100%{
background-image: url(test.jpg)
}
25%,45%{
background-image: url(test1.jpg)
}
50%,70%{
background-image: url(test2.jpg)
}
75%,95%{
background-image: url(test3.jpg)
}
}
新的动画进度图:

可以看出来经过修改后的动画,图片切换时刻基本跟25%,50%,75%,100%吻合。
2.2 进阶效果
先来看目标效果demo,从第一张滑动到最后一张再从最后一张往回滑动到第一张:

这样子带有滑入滑出效果的轮播,因为有了画面过渡,所以比单纯的图片切换在视觉体验上更流畅。
首先写HTML结构,注意这里这四张图其实在同一排的,滑动的时候使用transform: translateX
属性进行移动。
<div class="carousel-img-container">
<div class="carousel-img-scroll">
<div class="carousel-img" style="background-image: url(test.jpg)"></div>
<div class="carousel-img" style="background-image: url(test1.jpg)"></div>
<div class="carousel-img" style="background-image: url(test2.jpg)"></div>
<div class="carousel-img" style="background-image: url(test3.jpg)"></div>
</div>
</div>
再加上初始样式,让这四张图并排显示:
.carousel-img-container {
width: 130px;
height: 100px;
overflow: hidden;
}
.carousel-img-scroll {
width: 400%;
height: 100%;
display: flex;
animation: carousel 30s linear infinite normal;
}
.carousel-img {
width: 25%;
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
接下来是动画规则部分,仿照上面一个效果,这样写(如果只写0%,25%,50%,75%,100%时候的状态,那么就等效于使用from…to…语法,动画全程都在移动,不会有停留的时候):
@keyframes carousel{
0%,20%,100%{
transform: translateX(0)
}
25%,45%{
transform: translateX(-25%)
}
50%,70%{
transform: translateX(-50%)
}
75%,95%{
transform:translateX(-75%)
}
}
然而问题来了,95%到100%的状态,也就是transform:translateX(-75%)
到transform:translateX(0)
这一切换,明显不符合期望的效果,一瞬间就从最后一张到第一张。
接着修改,既然要往返效果,那么修改animation
属性中的animation-direction
子属性为alternate
(动画规则也需要修改)是不是就可以了?
animation: carousel 30s linear infinite alternate;
@keyframes carousel{
0%,20%{
transform: translateX(0);
}
25%,45%{
transform: translateX(-25%)
}
50%,70%{
transform: translateX(-50%)
}
75%,100%{
transform:translateX(-75%)
}
}
但是这样又有新的问题出现了:动画在最后一张图停留了非常长的时间,因为一来一回都要在第四张图上停留,所以就有了双倍的时间。
我解决这个问题的方法是:animation-direction
属性使用normal
值,不依靠CSS内置的往返运动,把整个往返一个来回当成一个运动周期,手动指定一个周期中每个时间点的状态。
从头再来分析一下这个动画过程,它一个周期的过程是这样子:
图1 → 图2 → 图3 → 图4 → 图3 → 图2 → 图1
划分阶段应该划分6个,每个就占总长度的16.6%,修改刚才的@keyframes
代码段:
@keyframes carousel{
0% {
transform: translateX(0)
}
16.6% {
transform: translateX(-25%)
}
33.2% {
transform: translateX(-50%)
}
49.8% {
transform:translateX(-75%)
}
66.4% {
transform:translateX(-50%)
}
83.0% {
transform:translateX(-25%)
}
100% {
transform:translateX(0)
}
}
然后为了让动画在每张图片上都有一个停留,继续修改,在每个移动时间点之前添加一段维持当前状态的规则:
@keyframes carousel{
0% {
transform: translateX(0)
}
13%{
transform: translateX(0)
}
16.6% {
transform: translateX(-25%)
}
29.6%{
transform: translateX(-25%)
}
33.2% {
transform: translateX(-50%)
}
46.2%{
transform: translateX(-50%)
}
49.8% {
transform:translateX(-75%)
}
62.8%{
transform:translateX(-75%)
}
66.4% {
transform:translateX(-50%)
}
79.4%{
transform:translateX(-50%)
}
83.0% {
transform:translateX(-25%)
}
96%{
transform:translateX(-25%)
}
100% {
transform:translateX(0)
}
}
现在,可以看看效果,是不是就跟一开始的demo一样呢。在这个动画中,为了图片滑动的效果能更流畅些,可以增加动画总时长,或者适当减少动画维持当前图片状态的时长(调整后来插入的时间点百分比即可),以留出更多时长给滑动效果。