使用 SVG 符號和 CSS 變量實現多彩圖標

使用 SVG 符號和 CSS 變量實現多彩圖標

使用 SVG 符號和 CSS 變量實現多彩圖標

使用圖片和 CSS 精靈製作 web 圖標的日子一去不復返了。隨著 web 字體的爆發,圖標字體已經成為在你的 web 項目中顯示圖標的第一解決方案。

字體是矢量,所以你無須擔心分辨率的問題。他們和文本一樣因為擁有 CSS 屬性,那就意味著,你完全可以應用 sizecolorstyle 。你可以添加轉換、特效和裝飾,比如旋轉、下劃線或者陰影。

怪不得類似 Font Awesome 這類項目僅僅在 npm 至今已經被下載了超過 1500 萬次。

可是圖標字體並不完美, 這就是為什麼越來越多的人使用行內 SVG 。CSS Tricks 寫了圖標字體劣於原生 SVG 元素的地方:銳利度、定位或者是因為跨域加載、特定瀏覽器錯誤和廣告屏蔽器等原因導致的失敗。現在你可以規避絕大多數這些問題了,總體上使用圖標字體是一個安全的選擇。

然而,還是有一件事情對於圖標字體來說是絕對不可能的:多色支持。只有 SVG 可以做到。

設置 SVG 標誌圖標

行內 SVG 的問題是,它會非常冗長。你肯定不想每次使用同一個圖標的時候,還需要複製/粘貼所有座標。這將會非常重複,很難閱讀,更難維護。

通過 SVG 符號圖標,你只需擁有一個 SVG 元素,然後在每個需要的地方引用就好了。

先添加行內 SVG ,隱藏它之後,再用 包裹它,用 id 對其進行識別。

  my-first-icon   

整個 SVG 標記被一次性包裹並且在 HTML 中被隱藏。

然後,所有你要做的是用一個 標籤將圖標實例化。

   

這將會顯示一個初始 SVG 圖標的副本。

**就是這樣了!**看起來很棒,是吧?

你可能注意到了這個有趣的 xlink:href 屬性:這是你的實例與初始 SVG 之間的鏈接。

需要提到的是 xlink:href 是一個棄用的 SVG 屬性。儘管大多數瀏覽器仍然支持,你應該用 **href** 替代。現在的問題是,一些瀏覽器比如 Safari 不支持使用 href 進行 SVG 資源引用,因此你仍然需要提供 xlink:href 選項。

安全起見,兩個都用吧。

添加一些顏色

不像是字體, color 對於 SVG 圖標沒有任何作用:你必須使用 fill 屬性來定義一個顏色。這意味著他們將不會像圖標字體一樣繼承父文本顏色,但是你仍然可以在 CSS 中定義它們的樣式。

// HTML    // CSS .icon { width: 100px; height: 100px; fill: red; }

在這裡,你可以使用不同的填充顏色創建同一個圖標的不同實例。

// HTML       // CSS .icon { width: 100px; height: 100px; } .icon-red { fill: red; } .icon-blue { fill: blue; }

這樣就可以生效了,但是不完全符合我們的預期。目前為止,我們所有做的事情可以使用一個普通的圖標字體來實現。我們想要的是在圖標的位置可以有不同的顏色。我們想要向每個路徑上填充不同顏色,而不需要改變其他實例,我們想要能夠在必要的時候重寫它。

首先,你可能會受到依賴於特性的誘惑。

// HTML   my-first-icon       
// CSS .icon-colors .path1 { fill: red; } .icon-colors .path2 { fill: green; } .icon-colors .path3 { fill: blue; }

不起作用。

我們嘗試設置 .path1.path2.path3 的樣式,彷彿他們被嵌套在 .icon-colors 裡,但是嚴格來說,並非如此 標籤不是一個會被你的 SVG 定義替代的佔位符。這是一個引用將它所指向內容複製為 shadow DOM

**那接下來我們該怎麼辦?**當子項不在 DOM 中時,我們如何才能用一個區域性的方式影響子項?

CSS 變量拯救世界

在 CSS 中,一些屬性從父元素繼承給子元素。如果你將一個文本顏色分配給 body

,這一頁中所有文本將會繼承那個顏色直到被重寫。父元素沒有意識到子元素,但是可繼承的樣式仍然繼續傳播。

現在有個問題:我們想傳遞不同顏色給原始 SVG 的不同路徑,但是隻能從一個 fill 屬性裡繼承。

這就需要 CSS 變量了。

.parent { --custom-property: red; color: var(--custom-property); }

所有 .parent 的子項都有紅色文本。

.parent { --custom-property: red; } .child { color: var(--custom-property); }

所有嵌套在 .parent 標籤裡的 .child 都有紅色文本。

現在,讓我們把這個概念應用到 SVG 符號裡去。我們將在 SVG 定義的每個部分使用 fill 屬性,並且設置成不同的 CSS 變量。然後,我們將給它們分配不同的顏色。

// HTML   my-first-icon         // CSS .icon-colors { --color-1: #c13127; --color-2: #ef5b49; --color-3: #cacaea; }

然後… 生效了 !

使用 SVG 符號和 CSS 變量實現多彩圖標

現在開始,為了用不同的顏色方案創建實例,我們所需要做的是創建一個新類。

// HTML    // CSS .icon-colors-alt { --color-1: brown; --color-2: yellow; --color-3: pink; }
.icon-monochrome { fill: grey; }

怎樣命名我的 CSS 變量?

當提到在 CSS 中命名,通常有兩條途徑:描述的或者語義的。描述的意思是告訴一個顏色是什麼:如果你存儲了 #ff0000 你可以叫它 --red 。語義的意思是告訴顏色它將會被如何應用:如果你使用 #ff0000 來給一個咖啡杯把手賦予顏色,你可以叫它 --cup-handle-color

描述的命名也許是你的本能。看起來更乾脆,因為#ff0000 除了咖啡杯把手還有更多地方可以被使用。一個

--red CSS 變量可被複用於其他需要變成紅色的圖標路徑。畢竟,這是實用主義在 CSS 中的工作方式。並且是一個良好的系統。

問題是,在我們的案例裡,我們不能把零散的類應用於我們想設置樣式的標籤。實用主義原則不能應用,因為我們對於每個圖標有單獨的引用,我們不得不通過類的變化來設置樣式。

使用語義類命名,例如 --cup-handle-color ,對於這個情況更有用。當你想改變圖標一部分的顏色時,你立即知道這是什麼以及需要重寫什麼。無論你分配什麼顏色,類命名將會一直關聯。

默認還是不要默認,這是個問題

將你的圖標的多色版本設置成默認狀態是很有誘惑力的選擇。這樣,你無需設置額外樣式,只需要在必要的時候可以添加你自己的類。

有兩個方法可以實現::rootvar() default

:root

:root 選擇器中你可以定義所有你的 CSS 變量。這將會把它們統一放在一個位置,允許你『分享』相似的顏色。 :root 擁有最低的優先度,因此可以很容易地被重寫。

:root { --color-1: red; --color-2: green; --color-3: blue; --color-4: var(--color-1); } .icon-colors-alt { --color-1: brown; --color-2: yellow; --color-3: pink; --color-4: orange; }

然而,這個方法有一個主要缺點。首先,將顏色定義與各自的圖標分離可能會有些讓人疑惑。當你決定重寫他們,你必須在類與 :root 選擇器之間來回操作。但是更重要的是,它不允許你去關聯你的 CSS 變量,因此讓你不能複用同一個名字。

var() 默認

你可以用 var() 功能來把一個 CSS 變量分配給一個屬性,並且它的第二個參數可以設置為某個默認值。

  my-first-icon    

設置默認值會很有用,但是這是一個折中方案。我建議你不要形成習慣,只在對給定項目有幫助的時候做這件事情。

How browser-friendly is all that?

CSS 變量與大多數現代瀏覽器兼容,但是就像你想的那樣, Internet Explorer 完全不兼容。因為微軟要支持 Edge 終止了 IE11 開發, IE 以後也沒有機會趕上時代了。

現在,僅僅是因為一個功能不被某個瀏覽器(而你必須適配)兼容,這不意味著你必須全盤放棄它。在這種情況下,考慮下優雅降級:給現代瀏覽器提供多彩圖標,給落後瀏覽器提供備份的填充顏色。

如果你使用 Sass 的話,這個可以被抽象為一個 @mixin

@mixin icon-colors($fallback: black) { fill: $fallback; @content; }

現在,你可以任意定義顏色方案而無需考慮瀏覽器兼容問題了。

.cup { @include icon-colors() { --cup-color: red; --smoke-color: grey; }; } .cup-alt { @include icon-colors(green) { --cup-color: green; --smoke-color: grey; }; }

在不同的瀏覽器中查看這個 pen 。在最新版本的 Firefox , Chrome 和 Safari 中,最後兩隻杯子各自擁有紅色杯身灰色煙氣和藍色杯身灰色煙氣。在 IE 和 版本號小於 15 的 Edge 中,第三個杯子的杯身與煙氣全部都是紅色,第四個則全部是藍色! ✨


分享到:


相關文章: