明天,分享一个理论业务中可能用得上的动画技巧。
巧用逐帧动画,配合补间动画实现一个有限循环的轮播成果,像是这样:
看到上述示意图,有同学不禁会提问,这不是个非常简单的位移动画么?
咱们来简略剖析剖析,从外表上看,的确如同只有元素的 transform: translate()
在位移,然而留神,这里有两个难点:
- 这是个有限轮播的成果,咱们的动画须要反对任意多个元素的有限轮播切换
- 因为是轮播,所以,运行到最初一个的时候,须要动画切到第一个元素
到这里,你能够暂停思考一下,如果有 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 动画,它对了解本文起着至关重要的作用。
好的,还是文章以结尾的例子,假如咱们存在这样 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>
首先,咱们实现这样一个简略的布局:
在这里,要实现轮播成果,并且是任意个数,咱们能够借助 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 变量就慌了,其实很好了解:
calc(var(--speed) * var(--s))
:单次动画的耗时 * 轮播的个数,也就是总动画时长steps(var(--s))
就是逐帧动画的帧数,这里也就是steps(6)
,很好了解calc(var(--s) * var(--h) * -1px))
单个 li 容器的高度 * 轮播的个数,其实就是 ul 的总体高度,用于设置逐帧动画的起点值
上述的成果,理论如下:
如果给容器增加上 overflow: hidden
,就是这样的成果:
这样,咱们就失去了整体的构造,至多,整个成果是循环的。
然而因为只是逐帧动画,所以只能看到切换,然而每一帧之间,没有过渡动画成果。所以,接下来,咱们还得引入补间动画。
利用补间动画实现两组数据间的切换
咱们须要利用补间动画,实现动静的切换成果。
这一步,其实也非常简单,咱们要做的,就是将一组数据,利用 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);
}
}
非常简单的一个动画:
基于上述成果,咱们如果把一开始提到的 逐帧动画 和这里这个 补间动画 联合一下,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));
}
}
就能失去这样一个成果:
Wow,神奇的化学反应产生了!基于 逐帧动画 和 补间动画 的联合,咱们简直实现了一个轮播成果。
当然,有一点瑕疵,能够看到,最初一组数据,是从第六组数据 transform 挪动向了一组空数据:
开端填充头部第一组数据
理论开发过轮播的同学必定晓得,这里,其实也很好解决,咱们只须要在开端,补一组头部的第一个数据即可:
革新下咱们的 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>
这样,咱们再看看成果:
Beautiful!如果你还有所纳闷,咱们给容器加上 overflow: hidden
,实际效果如下,通过额定增加的最初一组数据,咱们的整个动画刚好完满的连接上,一个完满的轮播成果:
残缺的代码,你能够戳这里:CodePen Demo — Vertical Infinity Loop
横向有限轮播
当然,实现了竖直方向的轮播,横向的成果也是一样的。
并且,咱们能够通过在 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);
}
}
这样,咱们就轻松的转化为了横向的成果:
残缺的代码,你能够戳这里:CodePen Demo — Horizontal Infinity Loop
轮播图?不在话下
OK,下面的只是文字版的轮播,那如果是图片呢?
没问题,办法都是一样的。基于上述的代码,咱们能够轻松地将它批改一下后失去图片版的轮播成果。
代码都是一样的,就不再列出来,间接看看成果:
残缺的代码,你能够戳这里:CodePen Demo — Horizontal Image Infinity Loop
把握了这个技巧之后,你能够将它使用在十分多只须要简化版的轮播成果之上。
再简略总结一下,十分有意思的技巧:
- 利用 逐帧动画,实现整体的轮播的循环成果
- 利用 补间动画 ,实现具体的 状态 A 向 状态 B * 的动画成果
- 逐帧动画 配合 补间动画 形成整体轮播的成果
- 通过向 HTML 构造开端补充一组头部数据,实现整体动画的连接
- 通过 HTML 元素的 style 标签,利用 CSS 变量,填入理论的参加循环的 DOM 个数,能够实现 JavaScript 与 CSS 的买通
最初
OK,本文到此结束,心愿本文对你有所帮忙 :)
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 — iCSS 前端趣闻 😄
更多精彩 CSS 技术文章汇总在我的 Github — iCSS,继续更新,欢送点个 star 订阅珍藏。
如果还有什么疑难或者倡议,能够多多交换,原创文章,文笔无限,满腹经纶,文中若有不正之处,万望告知。