踐:從設(shè)計稿到高性能圖標(biāo)與數(shù)據(jù)可視化)
1. 為什么 SVG 值得你花時間認(rèn)真對待SVG 這東西剛?cè)胄械臅r候我也沒太當(dāng)回事。不就是矢量圖嗎能畫圖標(biāo)、能縮放不失真完了。直到有一次接手一個數(shù)據(jù)可視化項(xiàng)目圖表里要渲染上千個動態(tài)節(jié)點(diǎn)用 Canvas 寫到手軟后來換成 SVG 重構(gòu)代碼量直接砍掉一半交互還更順滑。從那以后我才真正開始研究 SVG 的最佳實(shí)踐。SVG全稱 Scalable Vector Graphics可縮放矢量圖形。它本質(zhì)上是一種基于 XML 的標(biāo)記語言用來描述二維矢量圖形。跟 PNG、JPG 這類位圖最大的區(qū)別在于SVG 記錄的是圖形的幾何描述點(diǎn)、線、曲線、填充規(guī)則而不是像素矩陣。這意味著無論你把它放大到 4K 屏幕還是縮小到 16px 的 favicon它都能保持銳利的邊緣不會糊。那 SVG 到底能做什么簡單說網(wǎng)頁上你能看到的任何圖形SVG 幾乎都能畫。圖標(biāo)系統(tǒng)、Logo、數(shù)據(jù)圖表、地圖、動畫、交互式插圖、甚至復(fù)雜的 UI 組件背景都是 SVG 的用武之地。它可以直接嵌入 HTML可以用 CSS 控制樣式可以用 JavaScript 操作 DOM還能被壓縮成極小的文件體積。這篇文章適合誰看如果你正在做前端開發(fā)、UI 設(shè)計、數(shù)據(jù)可視化或者你只是想讓自己的網(wǎng)頁圖標(biāo)不再模糊那這篇內(nèi)容就是寫給你的。我會從實(shí)際項(xiàng)目出發(fā)把 SVG 的最佳實(shí)踐拆開揉碎包括代碼怎么寫、工具怎么選、性能怎么優(yōu)化、坑怎么避。不管你是剛接觸 SVG 的新手還是已經(jīng)用過一段時間但總覺得哪里不對勁的老手應(yīng)該都能從里面找到有用的東西。2. SVG 的核心設(shè)計思路與方案選型2.1 什么時候該用 SVG什么時候不該用這是最容易被忽略的問題。很多人一聽說 SVG 好就什么都往里塞結(jié)果項(xiàng)目里一堆 SVG 文件性能反而拉胯。我的經(jīng)驗(yàn)是圖標(biāo)、Logo、簡單插圖、數(shù)據(jù)圖表、需要交互或動畫的矢量圖形優(yōu)先用 SVG。而照片、復(fù)雜紋理、色彩層次極其豐富的圖像老老實(shí)實(shí)用位圖格式。為什么因?yàn)?SVG 的文件大小跟圖形復(fù)雜度成正比。一個簡單的箭頭圖標(biāo)SVG 可能只有 200 字節(jié)PNG 要 2KB。但一張風(fēng)景照片SVG 如果要精確還原每個像素的顏色變化文件會大到離譜而 JPG 可能只要 100KB。所以選型的核心判斷標(biāo)準(zhǔn)就一條這個圖形的幾何復(fù)雜度是否遠(yuǎn)低于它的像素復(fù)雜度。如果是SVG 贏如果不是位圖贏。還有一個場景要注意大量重復(fù)的簡單圖形。比如一個頁面要渲染 5000 個小圓點(diǎn)用 SVG 意味著 5000 個 DOM 節(jié)點(diǎn)瀏覽器布局和重繪的壓力會很大。這種情況 Canvas 更合適。但如果這 5000 個圓點(diǎn)需要各自響應(yīng)點(diǎn)擊事件、有獨(dú)立的 hover 效果那 SVG 的事件綁定優(yōu)勢又體現(xiàn)出來了。所以沒有絕對的對錯關(guān)鍵看你的交互需求。2.2 內(nèi)聯(lián) SVG vs 外部引用 vs CSS 背景SVG 在網(wǎng)頁中的使用方式主要有三種每種都有明確的適用場景。內(nèi)聯(lián) SVG就是把svg標(biāo)簽直接寫在 HTML 里。這種方式最大的好處是可以用 CSS 直接控制樣式用 JavaScript 直接操作內(nèi)部元素還能繼承父元素的顏色通過currentColor。適合需要動態(tài)交互、樣式繼承、動畫控制的場景。缺點(diǎn)是 HTML 文件會變大而且同一個 SVG 如果多處使用代碼會重復(fù)。外部引用是通過img srcicon.svg或object、iframe引入。優(yōu)點(diǎn)是瀏覽器可以緩存多處復(fù)用不重復(fù)加載。缺點(diǎn)是無法用外部 CSS 控制內(nèi)部樣式JavaScript 操作也受限同源策略下object可以操作但img完全不行。適合純展示、不需要動態(tài)改樣式的圖標(biāo)。CSS 背景是把 SVG 當(dāng)作background-image使用。適合裝飾性圖形、重復(fù)背景圖案。缺點(diǎn)同樣是無法精細(xì)控制內(nèi)部元素而且在高DPI屏幕下需要額外處理。我的建議是圖標(biāo)系統(tǒng)優(yōu)先用內(nèi)聯(lián) SVG 配合 symbol 復(fù)用這是目前最成熟的方案。具體做法是把所有圖標(biāo)定義在一個隱藏的svg里每個圖標(biāo)用symbol包裹然后通過use引用。這樣既避免了代碼重復(fù)又保留了樣式控制能力。svg styledisplay: none; symbol idicon-search viewBox0 0 24 24 circle cx11 cy11 r7 fillnone strokecurrentColor stroke-width2/ line x116 y116 x221 y221 strokecurrentColor stroke-width2/ /symbol /svg svg classiconuse href#icon-search//svg這種模式的好處是你只需要維護(hù)一份圖標(biāo)定義頁面里用use引用即可。改顏色直接改 CSS 的color屬性因?yàn)閟trokecurrentColor會繼承。2.3 viewBox 才是 SVG 的靈魂很多人寫 SVG 的時候只關(guān)注width和height忽略了viewBox。這是個大坑。viewBox定義了 SVG 的坐標(biāo)系和可視區(qū)域格式是viewBoxmin-x min-y width height。它決定了圖形在 SVG 畫布內(nèi)如何縮放和定位。舉個例子如果你有一個 24x24 的圖標(biāo)viewBox0 0 24 24然后你設(shè)置width48 height48圖形會自動放大兩倍而且邊緣依然銳利。但如果你不寫viewBox只寫width48 height48圖形不會縮放只會被裁剪或留白。更關(guān)鍵的是viewBox讓 SVG 具備了響應(yīng)式能力。你可以設(shè)置width100% height100%配合preserveAspectRatio屬性讓 SVG 自適應(yīng)容器大小。preserveAspectRatioxMidYMid meet是默認(rèn)值表示等比縮放并居中。如果你想讓圖形拉伸填滿容器可以用preserveAspectRationone但這通常會導(dǎo)致變形慎用。提示永遠(yuǎn)給 SVG 設(shè)置viewBox即使你覺得不需要。這是保證 SVG 可縮放、可復(fù)用的基礎(chǔ)。2.4 路徑數(shù)據(jù)優(yōu)化別讓設(shè)計師的導(dǎo)出文件直接上線從設(shè)計工具導(dǎo)出的 SVG往往包含大量冗余信息無用的命名空間、編輯器元數(shù)據(jù)、過長的路徑數(shù)據(jù)、不必要的分組。直接上線會導(dǎo)致文件體積膨脹甚至影響渲染性能。我一般會做這幾件事移除 XML 聲明和 DOCTYPE內(nèi)聯(lián)時不需要、刪除metadata和title以外的注釋、合并或刪除空g分組、簡化路徑數(shù)據(jù)。路徑簡化是最有效的一步可以用工具把貝塞爾曲線的精度從小數(shù)點(diǎn)后 6 位降到 2 位肉眼幾乎看不出區(qū)別但文件能小 30% 以上。還有一個技巧把path的fill和stroke屬性盡量提到父級或 CSS 里。如果多個路徑用同樣的顏色沒必要每個都寫一遍。用 CSS 類控制既減小體積又方便主題切換。3. 核心細(xì)節(jié)解析與實(shí)操要點(diǎn)3.1 坐標(biāo)系與變換理解 SVG 的數(shù)學(xué)基礎(chǔ)SVG 的坐標(biāo)系原點(diǎn)在左上角x 軸向右y 軸向下。這跟數(shù)學(xué)課本里的笛卡爾坐標(biāo)系不一樣剛開始可能會不習(xí)慣。所有元素的定位都是基于這個坐標(biāo)系。g元素是 SVG 里的分組容器可以給它加transform屬性來實(shí)現(xiàn)平移、旋轉(zhuǎn)、縮放。變換的順序很重要因?yàn)榫仃嚦朔ú粷M足交換律。transformtranslate(10, 20) scale(2)和transformscale(2) translate(10, 20)的結(jié)果完全不同。前者先平移再縮放后者先縮放再平移。我的經(jīng)驗(yàn)是先平移后縮放這樣平移的距離不會受到縮放倍數(shù)的影響更容易預(yù)測。還有一個容易踩的坑transform-origin在 SVG 里的默認(rèn)值是0 0而不是像 HTML 元素那樣默認(rèn)在中心。如果你想讓一個圖形繞自己的中心旋轉(zhuǎn)必須顯式設(shè)置transform-origin: center或者用transform-box: fill-box。這個坑我在做加載動畫的時候踩過圖形一直繞著畫布左上角轉(zhuǎn)排查了半天才發(fā)現(xiàn)是這個問題。3.2 樣式控制CSS 與屬性的優(yōu)先級博弈SVG 的樣式可以通過三種方式設(shè)置表現(xiàn)屬性如fillred、內(nèi)聯(lián)樣式如stylefill: red、外部 CSS如.icon { fill: red; }。它們的優(yōu)先級遵循 CSS 規(guī)則外部 CSS 和內(nèi)聯(lián)樣式會覆蓋表現(xiàn)屬性內(nèi)聯(lián)樣式優(yōu)先級高于外部 CSS除非外部用了!important。這里有個歷史遺留問題早期 SVG 規(guī)范里表現(xiàn)屬性的優(yōu)先級被設(shè)計得比較高導(dǎo)致 CSS 覆蓋不了?,F(xiàn)代瀏覽器已經(jīng)統(tǒng)一按 CSS 優(yōu)先級處理了但如果你要兼容很老的瀏覽器最好還是用 CSS 來控制樣式避免混用。另一個重點(diǎn)是currentColor。這個關(guān)鍵字會繼承父元素的color值是實(shí)現(xiàn)圖標(biāo)顏色跟隨文字顏色的關(guān)鍵。比如.icon { color: #333; } .icon:hover { color: #0066cc; }只要 SVG 內(nèi)部用了fillcurrentColor或strokecurrentColor圖標(biāo)顏色就會自動跟著變。這個技巧在做暗色模式切換的時候特別好用只需要改color變量所有圖標(biāo)自動適配。3.3 響應(yīng)式與自適應(yīng)讓 SVG 在任何屏幕上都好看SVG 的響應(yīng)式核心在于viewBox和preserveAspectRatio的配合。前面說了viewBox定義坐標(biāo)系preserveAspectRatio定義如何適配容器。默認(rèn)值xMidYMid meet表示等比縮放并居中這是最常用的。如果你想讓 SVG 填滿容器且不變形可以設(shè)置preserveAspectRatioxMidYMid slice這類似于 CSS 的background-size: cover會裁剪超出部分。但要注意裁剪可能會導(dǎo)致圖形邊緣被切掉適合背景圖案不適合圖標(biāo)。還有一個實(shí)用技巧用 CSS 控制 SVG 的尺寸而不是在 SVG 標(biāo)簽上寫死 width 和 height。這樣可以通過媒體查詢靈活調(diào)整。比如.icon { width: 1em; height: 1em; vertical-align: -0.125em; }用em單位讓圖標(biāo)大小跟隨文字大小vertical-align微調(diào)對齊。這是很多圖標(biāo)庫的標(biāo)準(zhǔn)做法實(shí)測下來在各種字體大小下都能保持視覺一致。3.4 動畫與交互SMIL vs CSS vs JavaScriptSVG 動畫有三種實(shí)現(xiàn)方式各有優(yōu)劣。SMILSynchronized Multimedia Integration Language是 SVG 原生的動畫方案用animate、animateTransform等標(biāo)簽實(shí)現(xiàn)。優(yōu)點(diǎn)是聲明式、不依賴 CSS 和 JS適合簡單的路徑動畫。缺點(diǎn)是性能一般而且 Chrome 曾經(jīng)考慮過廢棄它后來放棄了所以社區(qū)接受度不高。CSS 動畫是目前最推薦的方式。SVG 元素可以像 HTML 元素一樣用keyframes、transition做動畫。stroke-dasharray和stroke-dashoffset配合可以實(shí)現(xiàn)路徑描邊動畫這是做加載動畫和圖標(biāo)動效的經(jīng)典技巧。性能好代碼簡潔而且可以利用will-change做硬件加速。JavaScript 動畫適合復(fù)雜的交互邏輯比如根據(jù)用戶輸入實(shí)時改變圖形??梢杂胷equestAnimationFrame手動控制也可以用 GSAP、anime.js 這類動畫庫。靈活性最高但代碼量也最大。我的選擇順序是能用 CSS 就用 CSS需要復(fù)雜交互再上 JSSMIL 基本不用。CSS 動畫在 SVG 上的表現(xiàn)已經(jīng)很成熟了而且調(diào)試方便瀏覽器 DevTools 里可以直接改參數(shù)看效果。4. 實(shí)操過程與核心環(huán)節(jié)實(shí)現(xiàn)4.1 從設(shè)計稿到可用的 SVG 圖標(biāo)完整流程假設(shè)你從設(shè)計工具拿到了一個圖標(biāo)要把它變成項(xiàng)目里可用的 SVG。我一般會走這幾步。第一步導(dǎo)出優(yōu)化。設(shè)計工具導(dǎo)出的 SVG 通常包含大量冗余。我會先用 SVGO 做一輪壓縮。SVGO 是一個基于 Node.js 的 SVG 優(yōu)化工具可以移除元數(shù)據(jù)、合并路徑、簡化數(shù)值。命令行用法很簡單npx svgo input.svg -o output.svg默認(rèn)配置已經(jīng)能去掉大部分冗余。如果你想更激進(jìn)可以自定義插件配置比如把floatPrecision降到 2移除viewBox不推薦、合并style等。但要注意有些優(yōu)化可能會影響渲染效果比如合并路徑時如果填充規(guī)則不同可能會導(dǎo)致圖形錯亂。所以每次優(yōu)化后都要肉眼檢查一遍。第二步統(tǒng)一坐標(biāo)系。把圖標(biāo)的viewBox統(tǒng)一成0 0 24 24或0 0 16 16這是圖標(biāo)系統(tǒng)的常見做法。如果原始圖標(biāo)不是這個比例可以用設(shè)計工具調(diào)整或者手動改viewBox并微調(diào)路徑。統(tǒng)一坐標(biāo)系的好處是所有圖標(biāo)在同一個svg里引用時大小和位置自然對齊不需要額外調(diào)整。第三步清理樣式。把硬編碼的顏色改成currentColor把fill和stroke盡量提到 CSS 里。如果圖標(biāo)有多個顏色可以用 CSS 變量.icon-primary { --icon-color-1: #333; --icon-color-2: #999; }然后在 SVG 里用fillvar(--icon-color-1)。這樣切換主題時只需要改變量值。第四步封裝成 symbol。把所有圖標(biāo)放到一個隱藏的svg里每個圖標(biāo)用symbol包裹設(shè)置好id和viewBox。然后在頁面里用use引用。這個模式前面已經(jīng)演示過了這里不再重復(fù)。第五步按需加載。如果圖標(biāo)很多全部內(nèi)聯(lián)會導(dǎo)致 HTML 過大??梢杂?JavaScript 動態(tài)加載 SVG sprite 文件或者用構(gòu)建工具做代碼分割。我的做法是首屏需要的圖標(biāo)內(nèi)聯(lián)其余圖標(biāo)打包成單獨(dú)的 sprite 文件通過use hrefsprite.svg#icon-name引用?,F(xiàn)代瀏覽器對跨文件use的支持已經(jīng)不錯了但要注意同源策略和緩存問題。4.2 用 SVG 做數(shù)據(jù)可視化一個真實(shí)案例的拆解之前做過一個實(shí)時監(jiān)控面板需要展示服務(wù)器集群的健康狀態(tài)。每個節(jié)點(diǎn)是一個圓顏色表示狀態(tài)大小表示負(fù)載點(diǎn)擊可以展開詳情。用 SVG 實(shí)現(xiàn)下來代碼量比 Canvas 少很多而且交互邏輯特別清晰。核心結(jié)構(gòu)是這樣的svg viewBox0 0 800 600 classcluster-map g classnodes g classnode>const path document.querySelector(.my-path); const length path.getTotalLength(); path.style.strokeDasharray length; path.style.strokeDashoffset length;然后配合 CSS 動畫.my-path { animation: draw 2s ease forwards; } keyframes draw { to { stroke-dashoffset: 0; } }這里有個細(xì)節(jié)stroke-dasharray和stroke-dashoffset的值必須是長度單位不能是百分比。而且如果路徑有多個子路徑getTotalLength()返回的是所有子路徑的總長度描邊效果會依次經(jīng)過每個子路徑。如果你想讓每個子路徑獨(dú)立動畫需要分別處理。還有一個坑路徑的繪制方向會影響動畫的視覺效果。如果路徑是從右往左畫的描邊動畫也會從右往左。如果你想讓動畫從左往右需要確保路徑數(shù)據(jù)的方向是從左到右。這個在設(shè)計工具里導(dǎo)出時就要注意或者用工具反轉(zhuǎn)路徑方向。4.4 性能優(yōu)化什么時候該擔(dān)心什么時候不用SVG 的性能問題主要出現(xiàn)在兩個場景大量 DOM 節(jié)點(diǎn)和頻繁的屬性變更。大量 DOM 節(jié)點(diǎn)的問題前面提過了超過幾千個節(jié)點(diǎn)時瀏覽器的布局和重繪開銷會明顯增加。解決方案有幾種用 Canvas 替代、做虛擬化只渲染可視區(qū)域、合并簡單圖形為單個路徑。合并路徑是最有效的比如把 1000 個小圓點(diǎn)合并成一個pathDOM 節(jié)點(diǎn)從 1000 降到 1性能提升非常明顯。但代價是失去了獨(dú)立的事件綁定能力需要手動做命中檢測。頻繁的屬性變更比如用 JS 每幀更新cx、cy會觸發(fā)瀏覽器的樣式重算和重繪。優(yōu)化方法是用transform代替位置屬性因?yàn)閠ransform可以走 GPU 合成不觸發(fā)重排用 CSS 動畫代替 JS 逐幀更新用will-change提示瀏覽器提前優(yōu)化。但will-change不能濫用用多了反而會消耗內(nèi)存。我的經(jīng)驗(yàn)是100 個節(jié)點(diǎn)以內(nèi)隨便寫100 到 1000 個節(jié)點(diǎn)注意批量更新和避免布局抖動超過 1000 個節(jié)點(diǎn)認(rèn)真考慮 Canvas 或虛擬化。當(dāng)然這不是絕對數(shù)字具體還要看圖形復(fù)雜度和設(shè)備性能。5. 常見問題與排查技巧實(shí)錄5.1 SVG 不顯示或顯示異常的排查清單SVG 不顯示是最常見的問題原因可能有很多。我整理了一個排查順序按這個走基本能定位到問題?,F(xiàn)象可能原因排查方法完全空白viewBox缺失或錯誤檢查viewBox是否設(shè)置了合理的值完全空白路徑數(shù)據(jù)為空或格式錯誤在瀏覽器 DevTools 里檢查path的d屬性完全空白顏色與背景相同臨時加個strokered看看顯示但被裁剪viewBox范圍太小擴(kuò)大viewBox的寬高顯示但變形preserveAspectRatio設(shè)置不當(dāng)改回默認(rèn)值xMidYMid meet顯示但模糊沒有設(shè)置viewBox或尺寸不匹配確保viewBox和實(shí)際尺寸比例一致部分元素不顯示元素被其他元素遮擋調(diào)整 DOM 順序或z-index部分元素不顯示display: none或visibility: hidden檢查 CSS 繼承還有一個隱蔽的問題SVG 的width和height設(shè)置為 0。有時候從設(shè)計工具導(dǎo)出時如果畫板尺寸沒設(shè)置好導(dǎo)出的 SVG 可能寬高為 0自然什么都看不到。檢查一下這兩個屬性。5.2 跨瀏覽器兼容性那些年踩過的坑SVG 的瀏覽器兼容性整體很好但有些細(xì)節(jié)需要注意。use引用外部文件在部分瀏覽器里有限制尤其是跨域時。如果 sprite 文件和頁面不同源可能會被阻止。解決方案是把 sprite 內(nèi)聯(lián)到頁面里或者用 CORS 頭允許跨域。foreignObject在舊版瀏覽器里支持不好而且不同瀏覽器對內(nèi)部 HTML 的渲染有差異。如果要用建議做降級處理。text元素的字體在不同系統(tǒng)上渲染差異較大。如果對文字位置要求嚴(yán)格可以用textLength強(qiáng)制文字寬度或者把文字轉(zhuǎn)成路徑。但轉(zhuǎn)路徑后文字不可選中、不可搜索要權(quán)衡。CSStransform在 SVG 元素上的兼容性已經(jīng)沒問題了但transform-origin的默認(rèn)值差異需要注意。建議顯式設(shè)置transform-box: fill-box和transform-origin: center保證行為一致。5.3 文件體積優(yōu)化從 50KB 到 5KB 的實(shí)操記錄我優(yōu)化過一個從設(shè)計工具導(dǎo)出的 SVG 插圖原始文件 52KB最終壓到 4.8KB。過程是這樣的第一輪SVGO 默認(rèn)優(yōu)化。去掉了 XML 聲明、注釋、元數(shù)據(jù)、編輯器命名空間文件降到 38KB。這一步基本是無損的放心用。第二輪路徑精度降低。把floatPrecision從默認(rèn)的 3 降到 1文件降到 22KB。肉眼在正常尺寸下看不出區(qū)別但放大到 800% 時能看出輕微鋸齒。如果你的 SVG 需要支持超大尺寸展示精度別降太狠。第三輪合并路徑。把相同樣式的路徑合并成一個path文件降到 15KB。這一步需要小心如果路徑的填充規(guī)則不同nonzerovsevenodd合并后可能顯示異常。合并前先確認(rèn)所有路徑的fill-rule一致。第四輪移除隱藏元素和空分組。設(shè)計工具經(jīng)常導(dǎo)出一些不可見的輔助線、空g、重復(fù)的defs。手動清理后文件降到 9KB。第五輪用 CSS 替代重復(fù)屬性。把重復(fù)的fill、stroke提到 CSS 類里文件降到 6KB。第六輪gzip 壓縮。SVG 是文本格式gzip 壓縮率很高。服務(wù)器開啟 gzip 后實(shí)際傳輸體積只有 4.8KB。這一套流程下來體積減少了 90% 以上渲染性能也明顯提升。關(guān)鍵是每一步都要肉眼驗(yàn)證確保視覺效果沒有明顯損失。5.4 動態(tài)修改 SVG 樣式的正確姿勢用 JavaScript 修改 SVG 樣式時有幾個坑要注意。修改class比修改style更好。直接改element.style.fill red會生成內(nèi)聯(lián)樣式優(yōu)先級很高后續(xù)想用 CSS 覆蓋就麻煩了。更好的做法是切換 classelement.classList.add(is-active);然后在 CSS 里定義.is-active { fill: red; }。這樣樣式邏輯集中在 CSS 里JS 只負(fù)責(zé)狀態(tài)切換。修改viewBox要謹(jǐn)慎。動態(tài)改viewBox可以實(shí)現(xiàn)縮放和平移但頻繁修改會導(dǎo)致重繪。如果要做縮放交互建議用transform或者 CSSscale性能更好。批量修改用requestAnimationFrame。如果你要同時更新多個元素的屬性不要在循環(huán)里直接改而是收集起來在下一幀統(tǒng)一應(yīng)用。這樣可以避免多次重排。requestAnimationFrame(() { nodes.forEach(node { node.setAttribute(cx, newX); node.setAttribute(cy, newY); }); });5.5 圖標(biāo)系統(tǒng)的維護(hù)經(jīng)驗(yàn)最后分享一些圖標(biāo)系統(tǒng)維護(hù)的經(jīng)驗(yàn)。圖標(biāo)多了之后管理是個大問題。我的做法是統(tǒng)一命名規(guī)范。用icon-前綴加功能名比如icon-search、icon-user、icon-arrow-left。不要用icon-1、icon-2這種無意義的名字。建立圖標(biāo)清單。用一個 JSON 或 Markdown 文件記錄每個圖標(biāo)的名稱、用途、關(guān)鍵詞、添加日期。方便搜索和去重。我見過一個項(xiàng)目里同一個“關(guān)閉”圖標(biāo)有三份不同實(shí)現(xiàn)就是因?yàn)闆]人知道已經(jīng)有了。定期清理。每個迭代周期檢查一次把不再使用的圖標(biāo)刪掉。圖標(biāo)文件雖然小但積累多了也會影響構(gòu)建速度和維護(hù)成本。版本控制。圖標(biāo)變更要像代碼一樣走版本控制改了什么、為什么改都要有記錄。特別是圖標(biāo)的視覺調(diào)整最好附上對比截圖。提示如果團(tuán)隊里有設(shè)計師建議讓設(shè)計師直接維護(hù)圖標(biāo)源文件開發(fā)只負(fù)責(zé)導(dǎo)出和優(yōu)化。這樣職責(zé)清晰減少溝通成本。6. 我個人的一些實(shí)操體會SVG 這東西入門容易精通難。剛開始覺得不就是畫圖嗎用多了才發(fā)現(xiàn)細(xì)節(jié)特別多。我最大的體會是不要為了用 SVG 而用 SVG。選型的時候多問一句“這個場景真的需要矢量嗎”能省掉很多后續(xù)的麻煩。另一個體會是工具能自動化的事情不要手動做。SVG 優(yōu)化、圖標(biāo) sprite 生成、路徑精度調(diào)整這些都有成熟的工具鏈。花點(diǎn)時間配置好構(gòu)建流程比每次手動處理靠譜得多。我現(xiàn)在項(xiàng)目里用 SVGO 加自定義腳本導(dǎo)出即優(yōu)化基本不需要人工干預(yù)。還有就是多測試多驗(yàn)證。SVG 在不同瀏覽器、不同設(shè)備上的表現(xiàn)可能有細(xì)微差異。特別是涉及動畫和交互的時候一定要在真實(shí)設(shè)備上跑一遍。模擬器再方便也替代不了真機(jī)測試。最后說一個容易被忽略的點(diǎn)無障礙訪問。SVG 作為圖像應(yīng)該加上roleimg和aria-label讓屏幕閱讀器能正確識別。如果是裝飾性圖形加aria-hiddentrue避免干擾。這個細(xì)節(jié)很多項(xiàng)目都不注意但做起來其實(shí)很簡單對用戶體驗(yàn)的提升卻很實(shí)在。