CSS 实现无限循环轮播效果,根本不需要 JS

今天,分享一个实际业务中能够用得上的动画技巧。

巧用逐帧动画,配合补间动画实现一个无限循环的轮播效果,像是这样:

7834a4d967a7ca7473021b149603bb02.gif

看到上述示意图,有同学不禁会发问,这不是个非常简单的位移动画么?

我们来简单分析分析,从表面上看,确实好像只有元素的 transform: translate() 在位移,但是注意,这里有两个难点:

  1. 这是个无限轮播的效果,我们的动画需要支持任意多个元素的无限轮播切换

  2. 因为是轮播,所以,运行到最后一个的时候,需要动画切到第一个元素

到这里,你可以暂停思考一下,如果有 20 个元素,需要进行类似的无限轮播播报,使用 CSS 实现,你会怎么去做呢?

逐帧动画控制整体切换

首先,我需要利用到逐帧动画效果,也被称为步骤缓动函数,利用的是 animation-timing-function 中,的 steps,语法如下:

{
    /* Keyword values */
    animation-timing-function: step-start;
    animation-timing-function: step-end;
    /* Function values */
    animation-timing-function: steps(6, start)
    animation-timing-function: steps(4, end);
}

如果你对 steps 的语法还不是特别了解,强烈建议你先看看我的这篇文章 -- 深入浅出 CSS 动画[1],它对理解本文起着至关重要的作用。

好的,还是文章以开头的例子,假设我们存在这样 HTML 结构:

<div class="g-container">
  <ul>
    <li>Lorem ipsum 1111111</li>
    <li>Lorem ipsum 2222222</li>
    <li>Lorem ipsum 3333333</li>
    <li>Lorem ipsum 4444444</li>
    <li>Lorem ipsum 5555555</li>
    <li>Lorem ipsum 6666666</li>
  </ul>
</div>

首先,我们实现这样一个简单的布局:

68c549c51cf12bafa2e185022ef5e8e6.png

在这里,要实现轮播效果,并且是任意个数,我们可以借助 animation-timing-function: steps()

:root {
  // 轮播的个数
  --s: 6;
  // 单个 li 容器的高度
  --h: 36;
  // 单次动画的时长
  --speed: 1.5s;
}
.g-container {
  width: 300px;
  height: calc(var(--h) * 1px);
}
ul {
  display: flex;
  flex-direction: column;
  animation: move calc(var(--speed) * var(--s)) steps(var(--s)) infinite;
}
ul li {
  width: 100%;
}
@keyframes move {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(0, calc(var(--s) * var(--h) * -1px));
  }
}

别看到上述有几个 CSS 变量就慌了,其实很好理解:

  1. calc(var(--speed) * var(--s)):单次动画的耗时 * 轮播的个数,也就是总动画时长

  2. steps(var(--s)) 就是逐帧动画的帧数,这里也就是 steps(6),很好理解

  3. calc(var(--s) * var(--h) * -1px)) 单个 li 容器的高度 * 轮播的个数,其实就是 ul 的总体高度,用于设置逐帧动画的终点值

上述的效果,实际如下:

37e4106f0f731c9e608e1298c5de63ef.gif

如果给容器添加上 overflow: hidden,就是这样的效果:

43f0ba1a27f217a9c638fc14b33705c7.gif

这样,我们就得到了整体的结构,至少,整个效果是循环的。

但是由于只是逐帧动画,所以只能看到切换,但是每一帧之间,没有过渡动画效果。所以,接下来,我们还得引入补间动画。

利用补间动画实现两组数据间的切换

我们需要利用补间动画,实现动态的切换效果。

这一步,其实也非常简单,我们要做的,就是将一组数据,利用 transform,从状态 A 位移到 状态 B。

单独拿出一个来演示的话,大致的代码如下:

<div class="g-container">
  <ul style="--s: 6">
    <li>Lorem ipsum 1111111</li>
    <li>Lorem ipsum 2222222</li>
    <li>Lorem ipsum 3333333</li>
    <li>Lorem ipsum 4444444</li>
    <li>Lorem ipsum 5555555</li>
    <li>Lorem ipsum 6666666</li>
  </ul>
</div>
:root {
  --h: 36;
  --speed: 1.2s;
}
ul li {
  height: 36px;
  animation: liMove calc(var(--speed)) infinite;
}
@keyframes liMove {
  0% {
    transform: translate(0, 0);
  }
  80%,
  100%  {
    transform: translate(0, -36px);
  }
}

非常简单的一个动画:

591003d22db5ea2793db3e89de36fdef.gif
bgg1

基于上述效果,我们如果把一开始提到的 逐帧动画 和这里这个 补间动画 结合一下,ul 的整体移动,和 li 的 单个移动叠在在一起:

:root {
  // 轮播的个数
  --s: 6;
  // 单个 li 容器的高度
  --h: 36;
  // 单次动画的时长
  --speed: 1.5s;
}
.g-container {
  width: 300px;
  height: calc(var(--h) * 1px);
}
ul {
  display: flex;
  flex-direction: column;
  animation: move calc(var(--speed) * var(--s)) steps(var(--s)) infinite;
}
ul li {
  width: 100%;
  animation: liMove calc(var(--speed)) infinite;
}
@keyframes move {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(0, calc(var(--s) * var(--h) * -1px));
  }
}
@keyframes liMove {
  0% {
    transform: translate(0, 0);
  }
  80%,
  100%  {
    transform: translate(0, calc(var(--h) * -1px));
  }
}

就能得到这样一个效果:

20de615af4c80c74688a0ff439dbe839.gif

Wow,神奇的化学反应产生了!基于 逐帧动画补间动画 的结合,我们几乎实现了一个轮播效果。

当然,有一点瑕疵,可以看到,最后一组数据,是从第六组数据 transform 移动向了一组空数据:

8f9e0135d2656b25311db7699a479764.png

末尾填充头部第一组数据

实际开发过轮播的同学肯定知道,这里,其实也很好处理,我们只需要在末尾,补一组头部的第一个数据即可:

改造下我们的 HTML:

<div class="g-container">
  <ul>
    <li>Lorem ipsum 1111111</li>
    <li>Lorem ipsum 2222222</li>
    <li>Lorem ipsum 3333333</li>
    <li>Lorem ipsum 4444444</li>
    <li>Lorem ipsum 5555555</li>
    <li>Lorem ipsum 6666666</li>
    <!--末尾补一个首条数据-->
    <li>Lorem ipsum 1111111</li>
  </ul>
</div>

这样,我们再看看效果:

fc07689d13c4a5a45228ba5dc783f409.gif

Beautiful!如果你还有所疑惑,我们给容器加上 overflow: hidden,实际效果如下,通过额外添加的最后一组数据,我们的整个动画刚好完美的衔接上,一个完美的轮播效果:

4d442383de625f909dcec85b83963aba.gif

完整的代码,你可以戳这里:CodePen Demo -- Vertical Infinity Loop[2]

横向无限轮播

当然,实现了竖直方向的轮播,横向的效果也是一样的。

并且,我们可以通过在 HTML 结构中,通过 style 内填写 CSS 变量值,传入实际的 li 个数,以达到根据不同 li 个数适配不同动画:

<div class="g-container">
  <ul style="--s: 6">
    <li>Lorem ipsum 1111111</li>
    <li>Lorem ipsum 2222222</li>
    <li>Lorem ipsum 3333333</li>
    <li>Lorem ipsum 4444444</li>
    <li>Lorem ipsum 5555555</li>
    <li>Lorem ipsum 6666666</li>
    <!--末尾补一个首尾数据-->
    <li>Lorem ipsum 1111111</li>
  </ul>
</div>

整个动画的 CSS 代码基本是一致的,我们只需要改变两个动画的 transform 值,从竖直位移,改成水平位移即可:

:root {
  --w: 300;
  --speed: 1.5s;
}
.g-container {
  width: calc(--w * 1px);
  overflow: hidden;
}
ul {
  display: flex;
  flex-wrap: nowrap;
   animation: move calc(var(--speed) * var(--s)) steps(var(--s)) infinite;
}
ul li {
  flex-shrink: 0;
  width: 100%;
  height: 100%;
  animation: liMove calc(var(--speed)) infinite;
}
@keyframes move {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(calc(var(--s) * var(--w) * -1px), 0);
  }
}
@keyframes liMove {
  0% {
    transform: translate(0, 0);
  }
  80%,
  100%  {
    transform: translate(calc(var(--w) * -1px), 0);
  }
}

这样,我们就轻松的转化为了横向的效果:

b1a511b1afc687b709ec1f8728c80a56.gif

完整的代码,你可以戳这里:CodePen Demo -- Horizontal Infinity Loop[3]

轮播图?不在话下

OK,上面的只是文字版的轮播,那如果是图片呢?

没问题,方法都是一样的。基于上述的代码,我们可以轻松地将它修改一下后得到图片版的轮播效果。

代码都是一样的,就不再列出来,直接看看效果:

3000e1d590722199ad39280ec8cc70e8.gif

完整的代码,你可以戳这里:CodePen Demo -- Horizontal Image Infinity Loop[4]

掌握了这个技巧之后,你可以将它运用在非常多只需要简化版的轮播效果之上。

再简单总结一下,非常有意思的技巧:

  1. 利用 逐帧动画,实现整体的轮播的循环效果

  2. 利用 补间动画,实现具体的 *状态A状态B 的动画效果

  3. 逐帧动画 配合 补间动画 构成整体轮播的效果

  4. 通过向 HTML 结构末尾补充一组头部数据,实现整体动画的衔接

  5. 通过 HTML 元素的 style 标签,利用 CSS 变量,填入实际的参与循环的 DOM 个数,可以实现 JavaScript 与 CSS 的打通

参考资料

[1]

深入浅出 CSS 动画: https://github.com/chokcoco/iCSS/issues/141

[2]

CodePen Demo -- Vertical Infinity Loop: https://codepen.io/Chokcoco/pen/RwQVByx

[3]

CodePen Demo -- Horizontal Infinity Loop: https://codepen.io/Chokcoco/pen/JjpNBXY

[4]

CodePen Demo -- Horizontal Image Infinity Loop: https://codepen.io/Chokcoco/pen/GRQvqgq

[5]

Github -- iCSS: https://github.com/chokcoco/iCSS

最后

我是小前端,欢迎大家围观我的朋友圈,搞搞技术,吹吹牛逼。我的微信:kujian89,秒添加,邀你进入 500人前端群。

ad1c73e73025bd71f7e69e6d442c92f4.png

 
 
推荐阅读

深入浅出 CSS 动画

还在使用定时器吗?有点离谱的 CSS 电子时钟

20 个防御性的 CSS 实践

d795f36870fbc0084f177a49ca6fdf9a.png

关注公众号:前端开发博客

  1. 回复「小抄」,领取Vue、JavaScript 和 WebComponent 小抄 PDF

  2. 回复「Vue脑图」获取 Vue 相关脑图

  3. 回复「思维图」获取 JavaScript 相关思维图

  4. 回复「简历」获取简历制作建议

  5. 回复「简历模板」获取精选的简历模板

  6. 回复「加群」进入500人前端精英群

  7. 回复「电子书」下载我整理的大量前端资源,含面试、Vue实战项目、CSS和JavaScript电子书等。

  8. 回复「知识点」下载高清JavaScript知识点图谱

 👍🏻 点赞 + 在看 支持小编

### 回答1: 如何实现简易轮播图? 要实现简易轮播图,我们需要使用 HTMLCSSJavaScript。 1. 首先,在 HTML 中创建轮播图的容器元素,如 <div class="swiper-container"></div>。 2. 在 CSS 中设置容器元素的宽度和高度,以及每个轮播项(即图片)的宽度和高度。 3. 在 JavaScript 中获取容器元素和所有轮播项的元素,并将它们保存为变量。 4. 在 JavaScript 中设置一个定时器,每隔一定时间就切换下一张轮播项的显示。 5. 切换轮播项时,需要动态修改容器元素的 left 值,以使下一张轮播项出现在视图中。 6. 在 JavaScript 中处理轮播项的无限循环,即最后一张轮播项切换到第一张轮播项时,容器元素的 left 值需要设置为 0。 7. 最后,可以添加一些 UI 控件,如向左和向右箭头,用于手动切换轮播项的显示。 通过以上步骤,我们可以实现一个简易的轮播效果。 ### 回答2: 在Web开发中,轮播图是非常常见的一种交互效果轮播图通常由多张图片、标题、文本等内容组成,并自动或手动地在页面上轮播展示。本文将介绍使用HTMLCSSJavascript实现简易轮播图的方法。 首先,我们需要先设计页面布局和轮播图的样式。在HTML中,我们可以使用一个div元素作为轮播图的容器,并在其中创建多个子元素,每个子元素代表一张轮播图片。同时,在每个子元素上还可以添加标题、文本等元素。具体代码如下: ``` <div class="slider"> <div class="slider__item"> <img src="img1.jpg" alt="Slide 1"> <h3>Slide 1</h3> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> </div> <div class="slider__item"> <img src="img2.jpg" alt="Slide 2"> <h3>Slide 2</h3> <p>Nullam bibendum quam sed enim ultrices, ac pharetra tellus bibendum.</p> </div> <div class="slider__item"> <img src="img3.jpg" alt="Slide 3"> <h3>Slide 3</h3> <p>Etiam eget ligula in lectus varius porta quis sit amet quam.</p> </div> </div> ``` 在CSS中,我们可以设置轮播图容器的宽度、高度、背景色等属性,并将每个子元素设置为绝对定位,以实现叠加效果。具体样式代码如下: ``` .slider { width: 100%; height: 500px; position: relative; background-color: #f5f5f5; overflow: hidden; } .slider__item { position: absolute; top: 0; left: 0; right: 0; bottom: 0; opacity: 0; transition: opacity 1s ease-in-out; } .slider__item.active { opacity: 1; } ``` 在Javascript中,我们可以通过设置定时器来控制轮播图片的切换。具体做法是定义一个变量index表示当前展示的图片序号,在定时器中每隔一段时间将index自增1,并将当前图片的样式设置为.active。同时,如果index超过最大值,则将index重置为0,并从第一张图片重新开始轮播。具体Javascript代码如下: ``` let index = 0; const slides = document.querySelectorAll(".slider__item"); const maxIndex = slides.length - 1; setInterval(() => { slides[index].classList.remove("active"); index = (index === maxIndex) ? 0 : (index + 1); slides[index].classList.add("active"); }, 5000); ``` 通过以上步骤,我们就可以实现一个基础的轮播效果了。当然,为了增强用户的体验,我们还可以添加其他交互效果,比如滑动、点击等。同时,我们也需要注意优化代码的性能和可读性,以便实现更复杂、完善的轮播效果。 ### 回答3: 在网页设计中,轮播图被广泛应用,它可以用于展示多张图片或图片与文字的综合效果。本文将介绍如何使用HTMLCSSJavaScript实现简易轮播图。 首先,我们需要创建一个基本的HTML结构,包含一个div容器和多个图片元素。这些图片元素将被放置在div容器中,并且使用CSS调整它们的样式和位置。例如: ``` <div class="carousel"> <img src="image1.jpg"> <img src="image2.jpg"> <img src="image3.jpg"> </div> ``` 接下来,我们使用CSS调整div容器和图片元素的样式,创建一个适合展示轮播图的视觉效果。根据需要,可以使用float、width、height、margin和padding等属性调整元素的位置和间距。例如: ``` .carousel { width: 600px; height: 400px; margin: 0 auto; overflow: hidden; position: relative; } .carousel img { width: 100%; height: 100%; position: absolute; top: 0; left: 0; } ``` 在这里,我们将div容器的宽度设置为600像素,高度设置为400像素。将margin设置为0 auto,使其水平居中。通过设置overflow为hidden,实现图片元素的裁剪。将图片元素的宽度和高度分别设置为100%,以填充整个div容器。使用position:absolute属性和top、left属性将图片堆叠在一起。 最后,我们使用JavaScript函数和事件来实现轮播图的自动切换。我们可以使用setInterval函数在一定的时间间隔之后轮流显示每个图片元素。例如: ``` let slideIndex = 0; setInterval(() => { let slides = document.querySelectorAll('.carousel img'); slides[slideIndex].style.display = "none"; slideIndex = (slideIndex + 1) % slides.length; slides[slideIndex].style.display = "block"; }, 2000); ``` 在这里,我们首先创建一个slideIndex变量,用于跟踪显示的图片索引。使用setInterval函数创建一个按照固定时间间隔循环运行的匿名函数,在匿名函数中使用querySelectorAll函数选择所有图片元素,并在slideIndex变量中更新索引值。接着,在当前图片上应用style.display = "none"将其隐藏,将下一张图片显示出来。 综上所述,HTMLCSSJavaScript实现简易轮播图的三个必要组成部分。通过结合这三种技术,我们可以轻松地创建出一个具有自动切换功能的轮播图。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值