如何用 CSS 和 D3 創作一個用文字組成的心形圖案
阿新 • • 發佈:2018-12-08
效果預覽
線上演示按下右側的“點選預覽”按鈕可以在當前頁面預覽,點選連結可以全屏預覽。
https://codepen.io/comehope/pen/xJvERW
可互動視訊
此視訊是可以互動的,你可以隨時暫停視訊,編輯視訊中的程式碼。
請用 chrome, safari, edge 開啟觀看。
https://scrimba.com/p/pEgDAM/cm94eu6
原始碼下載
本地下載每日前端實戰系列的全部原始碼請從 github 下載:
https://github.com/comehope/front-end-daily-challenges
程式碼解讀
定義 dom,容器中包含 3 個子元素,每個子元素中有一個單詞:
<div class="love">
<span>aaa</span>
<span>bbb</span>
<span>ccc</span>
</div>
居中顯示:
body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: black; }
定義容器尺寸:
.love {
width: 450px;
height: 450px;
}
設定文字樣式:
.love {
position: relative;
}
.love span {
position: absolute;
left: 0;
color: goldenrod;
font-size: 20px;
font-family: sans-serif;
text-shadow: 0 0 1em white;
}
定義文字左右往復移動的動畫:
.love span { animation: x-move 10s ease-in-out infinite alternate; } @keyframes x-move { to { left: 450px; } }
定義子元素的下標變數,設定動畫延時,使各單詞依次入場:
.love {
--particles: 3;
}
.love span {
animation-delay: calc(20s / var(--particles) * var(--n) * -1);
}
.love span:nth-child(1) {
--n: 1;
}
.love span:nth-child(2) {
--n: 2;
}
.love span:nth-child(3) {
--n: 3;
}
增加文字沿心形運動的動畫效果:
.love span {
animation:
x-move 10s ease-in-out infinite alternate,
y-move 20s linear infinite;
}
@keyframes y-move {
0% { transform: translateY(180px); }
10% { transform: translateY(45px); }
15% { transform: translateY(5px); }
18% { transform: translateY(0); }
20% { transform: translateY(5px); }
22% { transform: translateY(35px); }
24% { transform: translateY(65px); }
25% { transform: translateY(110px); }
26% { transform: translateY(65px); }
28% { transform: translateY(35px); }
30% { transform: translateY(5px); }
32% { transform: translateY(0); }
35% { transform: translateY(5px); }
40% { transform: translateY(45px); }
50% { transform: translateY(180px); }
71% { transform: translateY(430px); }
72.5% { transform: translateY(440px); }
75% { transform: translateY(450px); }
77.5% { transform: translateY(440px); }
79% { transform: translateY(430px); }
100% { transform: translateY(180px); }
}
接下來用 d3 批量處理 dom 元素和 css 變數。
引入 d3 庫:
<script src="https://d3js.org/d3.v5.min.js"></script>
宣告一個數組,包含若干單詞:
const words = ['aaa', 'bbb', 'ccc'];
用 d3 建立 dom 元素:
d3.select('.love')
.selectAll('span')
.data(words)
.enter()
.append('span')
.text((d) => d);
用 d3 為 css 變數賦值:
d3.select('.love')
.style('--particles', words.length)
.selectAll('span')
.data(words)
.enter()
.append('span')
.style('--n', (d, i) => i + 1)
.text((d) => d);
刪除 html 檔案中相關的 dom 元素和 css 檔案中相關的 css 變數。
把陣列元素改為“愛”在各種語言的單詞:
const words = [
'愛', 'Love', 'Amour', 'Liebe', 'Amore',
'Amor', 'Любовь', 'الحب', 'प्यार', 'Cinta',
'Αγάπη', '사랑', 'Liefde', 'Dashuri', 'Каханне',
'Ljubav', 'Láska', 'Armastus', 'Mahal', 'אהבה',
'Szerelem', 'Grá', 'Mīlestība', 'Meilė', 'Любов',
'Љубовта', 'Cinta', 'عشق', 'Dragoste', 'Láska',
'Renmen', 'ፍቅር', 'munaña', 'Sevgi', 'Љубав',
'karout', 'amà', 'amôr', 'kærleiki', 'mborayhu',
'Upendo', 'sòòyayyàà', 'ljubav', 'Սեր', 'сүю',
'сүйүү', 'tia', 'aroha', 'KHAIR', 'प्रेम',
'kjærlighet', 'munay', 'jecel', 'Kärlek', 'soymek',
'Mahal', 'ярату', 'محبت', 'sopp', 'uthando',
'ความรัก', 'Aşk', 'Tình yêu', 'ליבע'];
最後,為第 1 個單詞設定特殊的文字樣式:
.love span:first-child {
color: orangered;
font-size: 3em;
text-shadow:
0 0 0.1em black,
0 0 1em white;
z-index: 1;
}
大功告成!