如何用 CSS 和 D3 創作旋臂粒子動畫
效果預覽
線上演示按下右側的“點選預覽”按鈕可以在當前頁面預覽,點選連結可以全屏預覽。
https://codepen.io/comehope/pen/xJrOqd
可互動視訊
此視訊是可以互動的,你可以隨時暫停視訊,編輯視訊中的程式碼。
請用 chrome, safari, edge 開啟觀看。
https://scrimba.com/p/pEgDAM/cr6Vetm
原始碼下載
本地下載每日前端實戰系列的全部原始碼請從 github 下載:
https://github.com/comehope/front-end-daily-challenges
程式碼解讀
定義 dom,容器中包含 6 個 內含 <span>
的 <div>
元素,每個 <div>
元素代表 1 個粒子:
<section class="container"> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div> </section>
居中顯示:
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: black;
}
定義容器尺寸:
.container {
width: 70vmin;
height: 70vmin;
}
在容器中定位 <div>
,並在 <div>
中用 <span>
畫出粒子:
.container { display: flex; align-items: center; justify-content: center; } .container div { position: absolute; width: 10vmin; height: 10vmin; } .container div span { position: absolute; width: inherit; height: inherit; border-radius: 50%; background-color: limegreen; transform: translateX(300%); }
用變數定義粒子的旋轉角度,其中 --particles-per-circle 每圈的粒子數,因為每圈有 3 個粒子,所以圈中有 3 個位置,每個位置有 2 個粒子重疊在一起,此時看起來是隻有 3 個粒子的樣子:
.container {
--particles-per-circle: 3;
}
.container div {
transform: rotate(calc(var(--n) / var(--particles-per-circle) * -360deg));
}
.container div:nth-child(1) {
--n: 1;
}
.container div:nth-child(2) {
--n: 2;
}
.container div:nth-child(3) {
--n: 3;
}
.container div:nth-child(4) {
--n: 4;
}
.container div:nth-child(5) {
--n: 5;
}
.container div:nth-child(6) {
--n: 6;
}
定義粒子從中心向外側的運動效果:
.container div span {
animation: move 2s linear infinite;
}
@keyframes move {
from {
transform: translateX(0) scale(0);
}
70% {
transform: translateX(210%) scale(0.55);
}
to {
transform: translateX(300%) scale(0);
}
}
再增加運動時讓粒子變色的效果,沿色相環取了 10 個顏色:
.container div span {
animation:
move 2s linear infinite,
change-color 2s linear infinite;
}
@keyframes change-color {
0%, 100% {
background-color: hsl(calc(0 / 100 * 360deg), 80%, 55%);
}
10% {
background-color: hsl(calc(10 / 100 * 360deg), 80%, 55%);
}
20% {
background-color: hsl(calc(20 / 100 * 360deg), 80%, 55%);
}
30% {
background-color: hsl(calc(30 / 100 * 360deg), 80%, 55%);
}
40% {
background-color: hsl(calc(40 / 100 * 360deg), 80%, 55%);
}
50% {
background-color: hsl(calc(50 / 100 * 360deg), 80%, 55%);
}
60% {
background-color: hsl(calc(60 / 100 * 360deg), 80%, 55%);
}
70% {
background-color: hsl(calc(70 / 100 * 360deg), 80%, 55%);
}
80% {
background-color: hsl(calc(80 / 100 * 360deg), 80%, 55%);
}
90% {
background-color: hsl(calc(90 / 100 * 360deg), 80%, 55%);
}
}
用變數設定動畫延時,這時可以看到 6 個粒子陸續出現了。其中 --circles 表示圈數;--particles 表示粒子數,它等於每圈的粒子數與圈數的積:
.container {
--circles: 2;
--particles: calc(var(--particles-per-circle) * var(--circles));
}
.container div span {
animation-delay: calc(var(--n) / var(--particles) * -2s);
}
接下來用 d3 來批量建立粒子。
引入 d3 庫:
<script src="https://d3js.org/d3.v5.min.js"></script>
用 d3 為 css 的 --particles-per-circle 和 --circles 變數賦值:
const PARTICLES_PER_CIRCLE = 3;
const CIRCLES = 2;
d3.select('.container')
.style('--particles-per-circle', PARTICLES_PER_CIRCLE)
.style('--circles', CIRCLES);
用 d3 建立粒子 dom 元素:
const COUNT_OF_PARTICLES = PARTICLES_PER_CIRCLE * CIRCLES;
d3.select('.container')
.style('--particles-per-circle', PARTICLES_PER_CIRCLE)
.style('--circles', CIRCLES)
.selectAll('div')
.data(d3.range(COUNT_OF_PARTICLES))
.enter()
.append('div')
.append('span');
用 d3 為粒子元素的 --n 變數賦值:
d3.select('.container')
.style('--particles-per-circle', PARTICLES_PER_CIRCLE)
.style('--circles', CIRCLES)
.selectAll('div')
.data(d3.range(COUNT_OF_PARTICLES))
.enter()
.append('div')
.style('--n', (d) => d + 1)
.append('span');
刪除掉 dom 中的粒子元素,以及用 css 宣告的變數。
最後,調整每圈的粒子數和圈數,形成旋臂效果:
const PARTICLES_PER_CIRCLE = 14;
const CIRCLES = 4;
大功告成!
原文地址:https://segmentfault.com/a/1190000015755660