話不多說,我們先上效果圖:
是不是很酷炫,這個效果是用SVG+CSS實現的,現在我們就來一起解構一下這個動畫的實現。
預備知識
需要掌握的幾個SVG的幾個標籤用法
-
<path>
指令 引數 說明 M x y 將畫筆移動到點(x,y) L x y 畫筆從當前的點繪製線段到點(x,y) H x 畫筆從當前的點繪製水平線段到點(x,y0) V y 畫筆從當前的點繪製豎直線段到點(x0,y) A rx ry x-axis-rotation large-arc-flag sweep-flag x y 畫筆從當前的點繪製一段圓弧到點(x,y) C x1 y1, x2 y2, x y 畫筆從當前的點繪製一段三次貝塞爾曲線到點(x,y) S x2 y2, x y 特殊版本的三次貝塞爾曲線(省略第一個控制點) Q x1 y1, x y 繪製二次貝塞爾曲線到點(x,y) T x y 特殊版本的二次貝塞爾曲線(省略控制點) Z 無引數 繪製閉合圖形,如果d屬性不指定Z命令,則繪製線段,而不是封閉圖形。 path的指令一共有9種,但實現我們的動畫我們只運用了其中兩個:A和Z,所以我們這裡著重討論一下A指令!
繪製圓弧指令:A rx ry x-axis-rotation large-arc-flag sweep-flag x y
對於給定兩個點(一個起點一個終點)和一個半徑,可以畫4條弧線。這四條弧線可以按照兩種分法:
- 按角度分
- 大於180°的
- 小於180°的
- 按畫筆方向分
- 順時針方向
- 逆時針方向
- 按角度分
-
rx,ry 是弧的半長軸、半短軸長度
-
x-axis-rotation 是圓弧旋轉角度,是此段弧所在的半長軸與水平方向的夾角。正數代表順時針轉動的角度。
-
large-arc-flag 為1 表示大角度弧線,0 代表小角度弧線。
-
sweep-flag 為1代表從起點到終點弧線繞中心順時針方向,0 代表逆時針方向。
-
x,y 是弧終端座標。
-
<defs>
SVG 允許我們定義以後需要重複使用的圖形元素。 建議把所有需要再次使用的引用元素定義在
defs
元素裡面。這樣做可以增加SVG內容的易讀性和可訪問性。 在defs
元素中定義的圖形元素不會直接呈現。 你可以在你的視口的任意地方利用 ``元素呈現這些元素。——MDN這個標籤的用意簡單地說就是定義一個繪圖模板,以供我們可以在別處直接使用。
在這裡我們可以定義我們的漸變元素:linearGradient。
-
<linearGradient>
linearGradient元素用來定義線性漸變,用於圖形元素的填充或描邊。——MDN
一個漸變上的顏色坡度,是用stop元素定義的。
例如:
<stop offset="5%" stop-color="#F60" /> 複製程式碼
這行程式碼的意思是:在距離起點位置偏移5%的地方顏色為 #F60。
我們在引用自己定義的漸變進行填充顏色設定或畫筆顏色設定時,僅需要用 url()的方式鏈入漸變的ID即可,具體如下:
stroke="url(#linear)" 複製程式碼
這裡我們將畫筆的顏色設定為了ID為linear的漸變。
還有兩個屬性:
-
stroke-dasharray
用於建立虛線:
stroke-dasharray = '10' stroke-dasharray = '10, 10' stroke-dasharray = '10, 10, 5, 5' 複製程式碼
繪製虛線: 一個引數時: 表示一段虛線長度和每段虛線之間的間距 。
兩個引數或者多個引數時:一個表示長度,一個表示間距
-
stroke-dashoffset
stroke-dashoffset 屬性指定了dash模式到路徑開始的距離
如果使用了一個 百分比值, 那麼這個值就代表了當前viewport的一個百分比。
值可以取為負值。——MDN
簡單的講,stroke-dashoffset設定的是畫筆起點的偏移量,正值向左偏移。
具體實現
畫SVG路徑
筆者通過描點,將網上下載下來的一張蘋果圖描出了SVG,可能不大精確,但是應該夠用。這裡放一下我描點的圖:
<path
stroke-linecap="round"
fill="none"
stroke-width="10"
stroke="url(#linear)"
d="
M 197,148
A 87,87,0,0,0,79,214
A 282,282,0,0,0,148,438
A 54,54,0,0,0,212,448
A 87,87,0,0,1,288,448
A 54,54,0,0,0,352,438
A 282,282,0,0,0,407,350
A 87,87,0,0,1,413,189
A 87,87,0,0,0,303,148
A 141,141,0,0,1,197,148
Z
"
/>
<path
stroke-linecap="round"
fill="none"
stroke="url(#linear)"
stroke-width="10"
d="
M 237,141
A 87,87,0,0,0,314,64
A 87,87,0,0,0,237,141
Z
"
/>
複製程式碼
並且我將我的畫筆顏色設定為即將編寫的漸變id。
定義漸變色
<defs>
<linearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="rgb(98, 180, 76)" />
<stop offset="20%" stop-color="rgb(242, 179, 61)" />
<stop offset="40%" stop-color="rgb(238, 125, 55)" />
<stop offset="60%" stop-color="rgb(205, 58, 71)" />
<stop offset="80%" stop-color="rgb(142, 61, 140)" />
<stop offset="100%" stop-color="rgb(39, 155, 213)" />
</linearGradient>
</defs>
複製程式碼
為了顯示為彩色,我設定了六個漸變顏色節點。
值得注意的是:漸變顏色的即便應用在畫筆上,他的填色還是按照面的顏色填充來填充的。就拿這個例子來說,我在linearGradient上定義了x1="0%" y1="0%" x2="100%" y2="100%",使頁面從左上角到右下角顏色顯示為漸變,而不是路徑的起點到終點的漸變,所以我們定義漸變在0%和100%的顏色並不需要一樣。(實際上我們也不能定義從路徑的起點到終點的漸變)
JavaScript獲取路徑長度
let pathLength = document.querySelectorAll('path');
pathLength.forEach((item, index) => {
let itemLength = Math.ceil(item.getTotalLength());
console.log(itemLength);
});
複製程式碼
這裡我們運用到了一個JavaScript API:getTotalLength(),用於獲取路徑長度,方便我們設定偏移量。
設定動畫
path {
animation: dash 5s linear forwards;
}
path:nth-child(2) {
stroke-dasharray: 1162;
stroke-dashoffset: -1162;
}
path:nth-child(3){
stroke-dasharray: 236;
stroke-dashoffset: -236;
}
@keyframes dash {
to {
stroke-dashoffset: 0;
}
}
複製程式碼
我們的動畫使從無到有的一個過程,所以我們將虛線長度和每段虛線之間的間距*都設定為路徑的長度。
在這種情況下我們顯示的應該是完整的蘋果logo。
當我們設定stroke-dashoffset為路徑長度的時候,那麼我們就將畫面的虛線部分完全隱藏在了畫筆起點之前。整個畫面將是空空如也!
這時候我們為兩個path新增動畫,讓其在5s之內勻速的改變stroke-dashoffset至0,那麼呈現在我們眼前的就是如前面的動圖所示,一個動態繪製logo的過程。
類似動畫的其他實現
先上效果圖:
實現程式碼如下:
<svg
xmlns="http://www.w3.org/2000/svg"
width="200px"
height="164.50px"
class="icon"
version="1.1"
viewBox="0 0 1245 1024"
id="logo-pic"
>
<defs>
<linearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#05a" />
<stop offset="100%" stop-color="#0a5" />
</linearGradient>
</defs>
<path
fill="url(#linear)"
d="M870.953514 333.768649c-209.781622 0-374.867027 145.020541-374.867028 322.836756s165.223784 322.836757 374.867028 322.836757a548.116757 548.116757 0 0 0 132.289729-22.417297L1124.185946 1024l-33.210811-110.702703C1179.537297 845.768649 1245.405405 756.92973 1245.405405 656.605405c0-177.816216-176.294054-322.836757-374.451891-322.836756z m-121.496217 267.208648A47.463784 47.463784 0 0 1 705.72973 556.419459 47.740541 47.740541 0 0 1 749.457297 512c33.349189 0 55.351351 22.278919 55.351352 44.557838s-22.002162 44.419459-55.351352 44.419459z m242.438919 0a47.325405 47.325405 0 0 1-43.727567-44.557838A47.602162 47.602162 0 0 1 991.896216 512c33.072432 0 55.351351 22.278919 55.351352 44.557838s-22.278919 44.419459-55.351352 44.419459z"
/>
<path
fill="url(#linear)"
d="M440.735135 0C198.434595 0 0 166.054054 0 378.326486c0 122.188108 66.006486 222.512432 176.432432 300.41946l-44.142702 133.811892 154.153513-77.907027c55.351351 10.931892 99.355676 22.278919 154.430271 22.278919 13.837838 0 27.675676 0 41.513513-1.798919a334.045405 334.045405 0 0 1-13.837838-93.267027c0-193.72973 166.054054-352.034595 374.728649-352.034595a378.88 378.88 0 0 1 42.482162 2.629189C847.429189 133.12 657.574054 0 440.735135 0zM294.192432 296.683243a53.137297 53.137297 0 1 1 52.722163-53.137297 52.860541 52.860541 0 0 1-52.722163 53.137297z m314.395676 0a53.137297 53.137297 0 1 1 52.722162-53.137297A52.860541 52.860541 0 0 1 608.864865 296.683243z"
/>
</svg>
<svg
xmlns="http://www.w3.org/2000/svg"
width="100%"
height="2rem"
id="logo-name"
>
<text
text-anchor="middle"
x="50%"
y="50%"
class="logo logo-name-text-1"
>
WeChat
</text>
<text
text-anchor="middle"
x="50%"
y="50%"
class="logo logo-name-text-2"
>
WeChat
</text>
<text
text-anchor="middle"
x="50%"
y="50%"
class="logo logo-name-text-3"
>
WeChat
</text>
</svg>
複製程式碼
值得注意的是,在SVG中文字也可以將邊框和填充分開來填色。所以這裡我們將文字的邊框設為最開始定義的漸變色,而填充設定為none。
#logo-pic {
width: 75px;
height: 75px;
}
.logo {
font-size: 1.25rem;
font-weight: bold;
fill: none;
stroke-width: 1px;
stroke-dasharray: 30% 70%;
animation: stroke 4.5s infinite linear;
}
.logo-name-text-1 {
stroke: rgb(0, 169, 86);
}
.logo-name-text-2 {
stroke: rgb(0, 127, 129);
animation-delay: -1.5s;
}
.logo-name-text-3 {
stroke: rgb(0, 86, 168);
animation-delay: -3s;
}
@keyframes stroke {
to {
stroke-dashoffset: -100%;
}
}
複製程式碼
筆者專門在 github 上建立了一個倉庫,用於記錄平時學習全棧開發中的技巧、難點、易錯點,歡迎大家點選下方連結瀏覽。如果覺得還不錯,就請給個小星星吧!?
2019/04/02