本文将介绍一种基于 CSS 变量技巧,通过正当应用 CSS 变量,实现 CSS 动画 @keyframes
的复用。
CSS 自定义变量
CSS 自定义变量大家应该都比拟相熟了,曾经不能算是新常识了,疾速过一遍。
CSS 自定义变量(CSS Variable),在之前也叫做 CSS 自定义属性,其应用形式如下:
// 申明一个变量::root{ --bgColor: #000;}
这里咱们借助了下面#12、结构性伪类
中的:root{ }
伪类,在全局:root{ }
伪类中定义了一个 CSS 变量,取名为--bgColor
。
定义完了之后则是应用,假如我要设置一个 div 的背景色为彩色:
.main{ background:var(--bgColor);}
这里,咱们在须要应用之前定义变量的中央,通过 var(定义的变量名)
来调用。
在 @keyframes 中应用 CSS 变量
OK,回归咱们的正题。巧用 CSS 变量,实现动画函数复用。
假如,咱们当初有多个元素,须要实现一个位移动画,从地位 A 位移到 地位 B,地位 A 雷同,然而地位 B 不一样,像是这样:
失常而言,因为起点不一样,咱们可能须要实现 3 个不一样的 @keyframes
,像是这样:
<ul> <li></li> <li></li> <li></li></ul>
li:nth-child(1) { animation: move1 2s linear;}li:nth-child(2) { animation: move2 2s linear;}li:nth-child(3) { animation: move3 2s linear;}@keyframes move1 { 60%, 100% { transform: translate(150px); }}@keyframes move2 { 60%, 100% { transform: translate(120px); }}@keyframes move3 { 60%, 100% { transform: translate(200px); }}
这个代码有问题吗?没有。
然而,咱们能够利用 CSS 变量,让它变得更为简洁,咱们革新一下 @keyframes
代码,将固定的位移值,变成一个变量:
@keyframes move { 60%, 100% { transform: translate(var(--dis)); }}
因为 CSS 变量是存在作用域的,咱们能够通过 CSS 变量的形式,给每一个 li 定义一个不同的 --dis
变量,像是这样:
li:nth-child(1) { --dis: 150px;}li:nth-child(2) { --dis: 120px;}li:nth-child(3) { --dis: 200px;}
这样,尽管动画的完结点不一样,然而咱们利用 CSS 变量,复用了同一个 @keyframes
函数:
通过内联 style 属性传入自定义变量
除了通过在 <style>
内传入不同的自定义变量,咱们还能够通过内联 style 属性传入自定义变量。
咱们再革新一下咱们的 @keyframes
:
@keyframes move { 60%, 100% { transform: translate(var(--end)); background: var(--color); }}
这一次,咱们不须要通过 :nth-child()
去批改每一个 li 的 CSS,而是通过 HTML 元素的内联 style
属性,像是这样:
<ul> <li style="--end: 150px; --color: red;"></li> <li style="--end: 200px; --color: blue;"></li> <li style="--end: 120px; --color: green;"></li></ul>
是的,每个 li 元素的 @keyframes
能够读取到每个 li 的 style
外面定义的不一样的 CSS 变量。
这样,咱们就能够失去如下成果:
残缺的代码,能够戳这里:CodePen Demo -- 巧用 CSS 变量,实现动画函数复用
实战演练
上面咱们实战演练一下,上一点难度。
在很久之前,咱们实现过这样一个动画成果:
这个动画成果的实现形式在于:
- 父级元素实现一个 rotateZ(360deg) 的匀速动画
- 子级元素实现一个反向的 rotateZ(-360deg) 的匀速动画
- 给父级元素增加一个 rotateX(40deg) 的动画
因为父容器和子容器同时相同向旋转,所以子元素看上去其实和没有旋转是一样的。然而因为又增加了一个 rotateX(40deg)
动画,因而看上去就会有这样一种 3D 成果。
在之前,咱们的代码是这样的:
<div class="reverseRotate"> <div class="rotate"> </div></div>
.rotate { animation: rotate 5s linear infinite; }.reverseRotate { animation: reverseRotate 5s linear infinite; }@keyframes rotate { 0% { transform: rotateX(0deg) rotateZ(0deg); } 50% { transform: rotateX(40deg) rotateZ(180deg); } 100% { transform: rotateX(0deg) rotateZ(360deg); }}@keyframes reverseRotate { 0% { transform: rotateZ(0deg); } 100% { transform: rotateZ(-360deg); }}
能够看到,咱们这里实现了两个动画成果:
@keyframes rotate {}
父容器的旋转动画@keyframes reverseRotate {}
子容器的旋转动画
其实,这里,使用明天的技巧,咱们能够把两个动画合成为一个,利用 CSS 自定义变量进行管制。革新后更简洁的 CSS 代码如下:
.rotate { --degZ: 360deg; --degZMiddle: 180deg; --degX: 30deg; animation: rotate 5s linear infinite; }.reverseRotate { --degZ: -360deg; --degZMiddle: -180deg; --degX: 0; animation: rotate 5s linear infinite; }@keyframes rotate { 0% { transform: rotateX(0deg) rotateZ(0deg); } 50% { transform: rotateX(var(--degX)) rotateZ(var(--degZMiddle)); } 100% { transform: rotateX(0deg) rotateZ(var(--degZ)); }}
是的,咱们能够失去同样的成果!
残缺的代码,你能够戳这里:CodePen DEMO -- Css动画正反旋转相消
图片旋转配合容器旋转
上面,咱们再来尝试一个有意思的动画成果,图片旋转配合容器旋转。
在上述的根底上,如果咱们把子元素,改成图片,整个成果就会有意思不少,咱们略微扭转一点点代码:
<div class="reverseRotate"> <img class="rotate" src="https://picsum.photos/1000/1000?random=5" alt=""></div>
.rotate,.reverseRotate { width: 60vh; height: 60vh;}.reverseRotate { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); border: 3px solid #999; overflow: hidden;}.rotate { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 100%; height: 100%;}.rotate { --degZ: 360deg; animation: rotate 5s linear infinite; }.reverseRotate { --degZ: -360deg; animation: rotate 5s linear infinite; }@keyframes rotate { 0% { transform: translate(-50%, -50%) rotateZ(0deg); } 100% { transform: translate(-50%, -50%) rotateZ(var(--degZ)); }}
这里,咱们做了什么事件呢?
- 去掉了 3D 成果
- 给外层容器加了边框
- 内层图片基于父容器相对定位,程度垂直居中
- 内外两层容器反向旋转 360° 动画
这样,咱们就能看到,尽管内外两层容器同时在进行相同方向的旋转 360° 动画,然而外部的图片其实是静止不动的!
成果如下:
因为,外部图片的大小为父容器的 100%
,所以在旋转过程中,父容器会有显著的无奈包裹住整个图片的状况。
这个很好解决,咱们只须要把图片大小调整大一点:
// ... 其它代码不变.rotate { width: 150%; height: 150%;}.rotate { --degZ: 360deg; animation: rotate 5s linear infinite; }
失常而言,对于正方形容器,外部图片设置到 141%
即可满足父容器旋转过程,能够始终包裹住图片的成果。那么,咱们就能失去这样一种成果:
残缺的代码,你能够戳这里:CodePen Demo -- Css动画正反旋转相消
Gird 布局配合正反旋转动画
当然,上述当只有一个容器的时候,整个动画成果还不够震撼。
如果咱们能够把这个成果交融进整个布局的动画之中,整个成果又会齐全不一样。
在 Rotating gallery with CSS scroll-driven animations 这篇文章中,作者提供了一种十分奇妙的思路,将 Grid 布局动画与上述动画成果奇妙的联合了起来。
首先,咱们利用 Gird 布局,实现这样一个简略的网格布局构造:
<div class="container"> <div class="A"> <img src="https://picsum.photos/600/600?random=1" alt=""></div> <div class="B"> <img src="https://picsum.photos/600/600?random=2" alt=""></div> <div class="C"> <img src="https://picsum.photos/600/600?random=3" alt=""></div> <div class="D"> <img src="https://picsum.photos/600/600?random=4" alt=""></div> <div class="E"> <img src="https://picsum.photos/600/600?random=5" alt=""></div></div>
.container { width: 60vmin; height: 60vmin; display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 1fr 1fr 1fr; gap: 4px; grid-template-areas: "E B B" "E A C" "D D C";}.container > div { border: 3px solid #431312; border-radius: 5px;}.A { grid-area: A;}.B { grid-area: B;}.C { grid-area: C;}.D { grid-area: D;}.E { grid-area: E;}
成果如下:
接下来,咱们要做的,就是联合下面的知识点,容器滚动起来,图片反向滚动起来,配合一些 tranfrom 变换。
有了下面的铺垫,上面的新增的代码就十分好了解了:
.container > div img { --scale: 1; --rotation: -360deg; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 260%; height: 260%; object-fit: cover; object-position: center;}.container,.container > div img { animation: 10s scale-up both ease-in-out infinite alternate;}@keyframes scale-up { 0% { transform: translate(-50%, -50%) scale(var(--scale)) rotate(0deg); } 100% { transform: translate(-50%, -50%) scale(1) rotate(var(--rotation)); }}
这样,咱们就失去了一个高级感拉满的网格旋转动画:
留神,这里咱们仍旧是通过 CSS 自定义变量,在不同元素间,复用了同一个动画 @keyframes
函数。
残缺的代码,你能够戳这里:CodePen Demo -- Grid 图片旋转动画 & 应用 CSS 变量复用动画函数
最初
好了,本文到此结束,心愿本文对你有所帮忙 :)
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,继续更新,欢送点个 star 订阅珍藏。
如果还有什么疑难或者倡议,能够多多交换,原创文章,文笔无限,满腹经纶,文中若有不正之处,万望告知。