任何有開發(fā)經(jīng)驗(yàn)的前端工程師都會(huì)考慮到不成體系的設(shè)備生態(tài)所帶來的挑戰(zhàn),。設(shè)備間不同的屏幕尺寸,、分辨率和比例使得產(chǎn)品難以提供一致的體驗(yàn),,對(duì)于那些對(duì)產(chǎn)品有著像素級(jí)完美追求的人這種體驗(yàn)差異尤其顯著,!SVG(可縮放的矢量圖形)完美地解決了上文中提到的部分問題,。盡管 SVG 有它的局限性,但是在某些場(chǎng)景下是非常有用的,,如果你有一個(gè)好的設(shè)計(jì)團(tuán)隊(duì),,你也可以基于SVG創(chuàng)建一些震撼的視覺體驗(yàn),而不必?fù)?dān)心給瀏覽器帶來過重的渲染負(fù)擔(dān)或阻礙頁面的加載時(shí)間,。
在過去的幾個(gè)月里,,我一直在做一個(gè)大量使用了 SVG 及其動(dòng)畫效果的項(xiàng)目。在本文中,,我將介紹如何使用SVG及其動(dòng)畫技術(shù)為你的 Web 前端開發(fā)帶來一些新鮮的體驗(yàn),。
可縮放矢量圖形
SVG 是一種基于 XML 文檔的圖片格式,所以大部分情況其特性表現(xiàn)類似于 HTML,。它為許多常見的幾何圖形定義了不同的元素,,通過組合這些不同的形狀元素可以生成 SVG 二維圖形。SVG 規(guī)范是由萬維網(wǎng)聯(lián)盟(W3C)于1999制定的標(biāo)準(zhǔn),,所有的主流瀏覽器目前均支持了 SVG 的渲染,。由于 SVG 圖形是 XML 文檔,因此 Web 瀏覽器提供的 DOM 相關(guān)的 API,,同樣可作用于與 SVG 圖形的交互,。
SVG 路徑
如果要說出 SVG 中最強(qiáng)大的元素,毫無疑問是 <path> (路徑元素),。
路徑元素是一個(gè)可以構(gòu)建出你所能想象的幾乎任何高級(jí)的2D圖形的基本形狀,。路徑元素通過一系列繪圖命令來生效,,它非常類似于1967年的 Logo 編程語言,不同的是它只是更現(xiàn)代化的,,為復(fù)雜花哨的圖形而設(shè)計(jì)的,。這些繪圖命令如下圖所示,被寫在路徑元素的 d 屬性中 :
<!-- A right-angled triangle -->
<path d="M10 10 L75 10 L75 75 Z" />
你可以把它想象成一支虛擬的畫筆在屏幕上作畫,,而路徑元素的 d 屬性中的繪圖命令控制著畫筆的走向,。上圖的示例中,畫筆一開始移動(dòng)到起點(diǎn)坐標(biāo) (10, 10) (M10 10 ),,以 (75, 10) 為終點(diǎn)畫直線(L75 10 ),,接著又畫一條直線至 (75, 75) (L75 75 ),最后的 Z 表示畫筆回到起點(diǎn)坐標(biāo)以閉合路徑,。
使用一些其他的繪圖命令,,例如繪圓弧(A ),、二次貝塞爾曲線(Q ),、三次貝塞爾曲線(C )等等,你可以在 SVG 中創(chuàng)建出很多組合的形狀和矢量圖形,。
你可以點(diǎn)擊這里了解更多關(guān)于路徑元素的知識(shí):
SVG 路徑與 CSS
也許你會(huì)問:“好吧我知道 Paths 很強(qiáng)大,,但是我怎樣才能對(duì)它做路徑動(dòng)畫呢?”,。
因此我們第一步需要利用到 SVG 的兩個(gè)屬性:stroke-dasharray 和 stroke-dashoffset ,。
stroke-dasharray 屬性可以控制圖案描邊路徑的樣式,如果你并不想用連續(xù)的直線去繪制路徑,,而希望通過一些不同樣式的虛線,,你就可以使用這個(gè)屬性。
由于 SVG 圖形其實(shí)也是瀏覽器 DOM 的組成部分,,因此 stroke-dasharray 作為一個(gè)控制外觀的屬性,,也可以直接用作一個(gè) CSS 樣式屬性,達(dá)到同樣的設(shè)置效果,。
類似的,,stroke-dashoffset 屬性(虛線在原路徑下的偏移量)也同樣可以使用 CSS 來進(jìn)行設(shè)置。
這兩個(gè)屬性的組合使用可以生成 SVG 路徑動(dòng)畫,,給人一種圖案的輪廓線逐漸擬合的視覺感受,。
例如下面這個(gè)二次貝塞爾曲線的例子:
<path fill="transparent" stroke="#000000" stroke-width="5" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="path"></path>
為了平穩(wěn)流暢地繪制出這個(gè)路徑,首先我們需要通過 stroke-dasharray 屬性設(shè)置虛線段的長(zhǎng)度,,將 stroke-dasharray 屬性的值設(shè)為該路徑的長(zhǎng)度,。這樣的話就將虛線的每一段 dash 和 gap 的長(zhǎng)度等于整段路徑的長(zhǎng)。
下一步我們需要使用 stroke-dashoffset 屬性將虛線的偏移量設(shè)置為 0 ,,此時(shí)我們看到的路徑描邊就是沒有間斷的連續(xù)曲線(實(shí)際上看到的是虛線段的第一段,,前面已經(jīng)設(shè)置每一虛線段的長(zhǎng)度等于該曲線的長(zhǎng)),。通過設(shè)置虛線偏移量等于曲線的長(zhǎng)度,那該曲線恰好“消失”(實(shí)際上看到的是虛線段的一段間隙),。
通過 stroke-dashoffset 屬性,,同時(shí)結(jié)合 CSS3 的 animation ,你可以讓該曲線一點(diǎn)點(diǎn)的出現(xiàn)在屏幕上,,這就是 SVG 路徑動(dòng)畫的原理,。
<svg width="300px" height="175px" version="1.1">
<path fill="transparent" stroke="#000000" stroke-width="4" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="path"></path>
</svg>
svg {
width: 300px;
display: block;
position: absolute;
.path {
stroke-dasharray: 320;
stroke-dashoffset: 0;
animation: dash 1s linear;
}
@keyframes dash {
from {
stroke-dashoffset: 320;
}
to {
stroke-dashoffset: 0;
}
}
}
你可以點(diǎn)擊這里查看 CODEPEN 上的 DEMO。
可以看到,,我們只是改變了虛線的偏移來讓虛線段的部分一點(diǎn)一點(diǎn)地出現(xiàn),。
運(yùn)用相同的原理來設(shè)置多條路徑的動(dòng)畫,可以得到更炫酷的效果:
<svg width="300px" height="175px" version="1.1">
<path fill="transparent" stroke="#000000" stroke-width="4" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="path"></path>
<path fill="transparent" stroke="#FF2851" stroke-width="4" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="line2"></path>
<path fill="transparent" stroke="#000000" stroke-width="4" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="line1"></path>
</svg>
svg {
width: 300px;
display: block;
position: absolute;
}
svg .line1 {
stroke-dasharray: 340;
stroke-dashoffset: 40;
animation: dash 1.5s linear alternate infinite;
}
svg .line2 {
stroke-dasharray: 320;
stroke-dashoffset: 320;
animation: dash2 1.5s linear alternate infinite;
}
@keyframes dash {
from {
stroke-dashoffset: 360;
}
to {
stroke-dashoffset: 40;
}
}
@keyframes dash2 {
from {
stroke-dashoffset: 280;
}
to {
stroke-dashoffset: -40;
}
}
你可以點(diǎn)擊這里查看 CODEPEN 上的 DEMO,。
上面在 SVG 中畫了3 條路徑:其中一條是固定的黑色曲線, 有一條沿著路徑移動(dòng)的紅色曲線,,后面跟著另一條黑色曲線,。
stroke-dasharray 和 stroke-dashoffset 是創(chuàng)造大量 SVG 路徑動(dòng)畫所要用到的兩個(gè)重要屬性,你可以點(diǎn)擊這里(一個(gè)方便的小工具)來體會(huì)這兩個(gè)屬性,。
有關(guān)于stroke-dasharray 和 stroke-dashoffset 相關(guān)的介紹可以點(diǎn)擊這里閱讀,。
沿 SVG 路徑的動(dòng)畫對(duì)象
通過 SVG 和 CSS,我們可以讓一個(gè)對(duì)象或者元素沿著 SVG 路徑做一些動(dòng)效,,過程中我們會(huì)用到兩個(gè)屬性:
offset-path :offset-path 是一個(gè) CSS 屬性,,它表示元素的運(yùn)動(dòng)路徑;
offset-distance :同樣是一個(gè) CSS 屬性,,定義了元素在路徑上運(yùn)動(dòng)的距離,,單位是數(shù)值或百分比;
通過組合使用這兩個(gè)屬性,,你可以非常容易地創(chuàng)建出類似下面的動(dòng)畫:
<svg width="300px" height="175px" version="1.1">
<path fill="transparent" stroke="#888888" stroke-width="1" d="M10 80 Q 77.5 10, 145 80 T 280 80" class="path"></path>
</svg>
<div class="ball"></div>
svg {
width: 300px;
display: block;
position: absolute;
}
.ball {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
offset-path: path('M10 80 Q 77.5 10, 145 80 T 280 80');
offset-distance: 0%;
animation: red-ball 2s linear alternate infinite;
}
@keyframes red-ball {
from {
offset-distance: 0%;
}
to {
offset-distance: 100%;
}
}
你可以點(diǎn)擊這里查看 CODEPEN 上的 DEMO,。
上面我們讓一個(gè) div.ball 的元素動(dòng)了起來,同樣的我們可以對(duì)任何元素(div , image , text ...)做這種路徑動(dòng)畫,。在這個(gè)例子中我們簡(jiǎn)單的用 offset-path 畫出了元素的運(yùn)動(dòng)路徑,,然后用 offset-distance 控制元素在路徑上的運(yùn)動(dòng)距離從 0% 到100% 。
使用 JavaScript 做 SVG 動(dòng)畫
以上如果還不足以滿足你的動(dòng)畫需求,,你可以考慮借助 JavaScript,。
使用 JavaScript 對(duì) SVG 元素做動(dòng)畫與對(duì) DOM 元素做動(dòng)畫相似。然而我們可以更容易地實(shí)現(xiàn)上面提到的動(dòng)畫效果,。之前,,我們需要將路徑長(zhǎng)度硬編碼在 CSS 中。借助 JavaScript 的 path.getTotalLength() 函數(shù)可以獲取 DOM 上路徑的長(zhǎng)度,,你可以點(diǎn)擊這里了解更多,。除此之外,,有很多第三方庫可以幫助你十分容易地制作 SVG 動(dòng)畫。
Snap.svg 不僅可以使 JavaScript 繪制 SVG 圖形變得更容易,,它的使用也異常簡(jiǎn)單,,只需要調(diào)用 .animate({}) 這個(gè)API即可。 另外一個(gè)庫 anime.js 通過幾行代碼就可以讓一個(gè)元素沿著 SVG 路徑運(yùn)動(dòng),,點(diǎn)擊這里 ??锤?DEMO。
如果你需要一個(gè)本身已經(jīng)為你做了大部分操作來生成復(fù)雜的動(dòng)畫的庫,,Vivus 是比較適合你的,,它采取了一種不同的調(diào)用方式,僅需要通過配置項(xiàng)的方式去生成 SVG 路徑動(dòng)畫,。你只需要用你想作用的 SVG 元素的 id 來新建一個(gè) Vivus 對(duì)象,,然后就交給 Vivus 來處理剩下的事情。
拓展閱讀
本文轉(zhuǎn)載自:眾成翻譯
譯者:@Gardon Lee
鏈接:http://www./article/4357
原文:https://www./front-end/svg-animation-guide
原文鏈接://www./front-end/svg-animation-guide
作者:@JUAN CALOU
|