本文將介紹一種基於 CSS 變數技巧,通過合理使用 CSS 變數,實現 CSS 動畫 @keyframes
的複用。
CSS 變數大家應該都比較熟悉了,已經不能算是新知識了,快速過一遍。
CSS 變數(CSS Variable),在之前也叫做 CSS 自定義屬性,其使用方式如下:
// 宣告一個變數:
:root{
--bgColor: #000;
}
這裡我們藉助了上面
#12、結構性偽類
中的:root{ }
偽類,在全域性:root{ }
偽類中定義了一個 CSS 變數,取名為--bgColor
。
定義完了之後則是使用,假設我要設定一個 div 的背景色為黑色:
.main{
background:var(--bgColor);
}
這裡,我們在需要使用之前定義變數的地方,通過 var(定義的變數名)
來呼叫。
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 屬性傳入自定義變數。
我們再改造一下我們的 @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">
由於,內部圖片的大小為父容器的 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">
接下來,我們要做的,就是結合上面的知識點,容器捲動起來,圖片反向捲動起來,配合一些 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 變數複用動畫函數
最後
好了,本文到此結束,希望本文對你有所幫助