最近,群友貼了一個非常有意思的動畫效果,整體動畫效果如下: ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9767a38b3ec04e3fb3082daed7ac75a0~tplv-k3u1fbpfcp-watermark.image?) ...
最近,群友貼了一個非常有意思的動畫效果,整體動畫效果如下:
點擊某個按鈕後,觸發一個動畫效果,原本的網格內容,將按順序(又帶點隨機的效果)從高處下落進行載入填充動畫。
當然,我個人認為這個動畫有點華而不實,主要體現在這個動畫一次需要耗費較長時間,有點消磨人的耐心。不過確實一個很好的 CSS 動畫教學案例。
而本文,就將具體去剖析這個動畫,如果使用純 CSS,應該如何實現。
還原佈局結構
首先,我們需要大致還原佈局結構,這個並非整個動畫的核心。
整個動畫的核心在於元素按順序(又帶點隨機的效果)從高處下落漸次進行下落載入填充動畫。
當然,還原這個佈局也非常簡單,這裡我們藉助 flex 佈局快速實現,幾個關鍵點:
- 每個 flex-item 寬度不固定:這一點可以使用 SASS 函數進行模擬,隨機生成不同寬度的 flex-item
- 每個 flex-item 背景色隨機:這一點同樣也可以藉助 SASS 函數 實現
- 整體水平居中:這個也簡單,父容器添加
justify-content: center;
即可
這樣,整個佈局的大致代碼如下:
<ul>
<li></li>
<li></li>
// ... 假設一共 50 個 li
<li></li>
</ul>
$count: 51;
@function randomNum($max, $min: 0, $u: 1) {
@return ($min + random($max)) * $u;
}
@function randomColor() {
@return rgb(randomNum(255), randomNum(255), randomNum(255));
}
ul {
display: flex;
gap: 4px;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
width: 640px;
height: 420px;
}
li {
flex-shrink: 0;
height: 30px;
border-radius: 30px;
}
@for $i from 1 to $count {
li:nth-child(#{$i}) {
width: #{randomNum(110, 90)}px;
background: randomColor();
}
}
簡單解釋一下:
- 利用了 SASS 的迴圈函數簡化代碼量
- 實現了兩個 SASS 函數,利用這兩個函數隨機生成不同寬度不同顏色的 li
randomNum()
: 用於生成範圍內的隨機數randomColor()
: 用於生成隨機顏色值
這樣,我們就可以快速得到這樣一個佈局效果:
下落動畫
接下來,我們來實現元素的下落動畫。
首先,我們撇開多元素的按順序又帶點隨機的延遲下落,值聚焦於單個 item 的下落動畫,它其實是這麼個動畫效果:
整個動畫的核心步驟大致是:
- 預設是狀態下,元素是在最終的 flex 佈局狀態下,且是可見狀態
- 動畫開始時,元素將消失,然後從上方,在一個縮小狀態下,有一個小幅度向上運動
- 接著元素向下運動到目標位置(終止狀態)
- 元素從縮小狀態,放大為正常狀態
- 並且,動畫結束後,需要維持在最後一幀,因此需要使用(
animation-fill-mode: forwards
)
對 CSS 動畫細節和各個屬性還不太瞭解的,建議你看看我的這本小冊 -- CSS 技術揭秘與實戰通關
完成上面的拆解後,單個動畫實現起來就非常輕鬆了:
li {
opacity: 0;
&hover {
animation: falldown 1s forwards;
}
}
@keyframes falldown {
0% {
transform: translateY(-180px) scaleX(.1) scaleY(.3);
opacity: 1;
}
20% {
transform: translateY(-200px) scaleX(.6) scaleY(.3);
}
75% {
transform: translateY(0) scaleX(.6) scaleY(.3);
}
100% {
transform: translateY(0) scaleX(1) scaleY(1);
opacity: 1;
}
}
這樣,我們就輕鬆的實現了單個的動畫效果:
如果 50 個 item 同時作用這個動畫,就是這樣的效果:
實現延遲隨機下落
當然,到這裡,整個動畫都還是平平無奇的。
我們需要最後的點睛之筆,實現按順序又帶點隨機的延遲下落效果,以及讓整體的動畫更加自然。
這裡的核心就在於:
- 利用
animation-delay
製造延遲效果,但是不能是順序延遲,需要帶點隨機效果 - 利用
animation-timing-function
緩動函數,控制動畫的速度曲線,使動畫變化更為平滑 - 控制縮短每一個 item 的動畫時長
方法明確了,剩下的就是調試動畫效果了,最終,經過一番調試,完整的動畫效果的代碼就完成啦。
代碼量真的不多:
$count: 51;
@function randomNum($max, $min: 0, $u: 1) {
@return ($min + random($max)) * $u;
}
@function randomColor() {
@return rgb(randomNum(255), randomNum(255), randomNum(255));
}
ul {
display: flex;
gap: 4px;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
width: 660px;
height: 420px;
}
li {
flex-shrink: 0;
height: 30px;
border-radius: 30px;
}
@for $i from 1 to $count {
li:nth-child(#{$i}) {
width: #{randomNum(110, 90)}px;
background: randomColor();
}
}
ul:hover {
li {
opacity: 0;
}
@for $i from 1 to $count {
li:nth-child(#{$i}) {
animation: falldown .3s cubic-bezier(.44,.02,.65,1.3) #{50 * ($count - $i) + (random(150) - random(300))}ms forwards;
}
}
}
@keyframes falldown {
0% {
transform: translateY(-180px) scaleX(.1) scaleY(.3);
opacity: 1;
}
20% {
transform: translateY(-200px) scaleX(.6) scaleY(.3);
}
75% {
transform: translateY(0) scaleX(.6) scaleY(.3);
}
100% {
transform: translateY(0) scaleX(1) scaleY(1);
opacity: 1;
}
}
核心,就在於這一句,animation: falldown .3s cubic-bezier(.44,.02,.65,1.3) #{50 * ($count - $i) + (random(150) - random(300))}ms forwards
,需要好好的消化理解。
這樣,我們就基本完美的復刻了原效果:
Gif 錄製存在掉幀行為,原效果會比 GIF 錄製出來的更好。完整的代碼你可以戳這裡:
CodePen Demo -- Flex Item Fall Down
總結一下
好了,本文到此結束,希望對你有幫助