昨天介紹的 fill 與 stroke 只能處理單色,不免讓人覺得拿 SVG 設定 icon 有點殺雞焉用牛刀。別急別急,今天就是分享如何在 inline SVG 製作漸層效果。
聰明的你,一定馬上想到能用 CSS 的 background: linear-gradient(…) 屬性做漸層,搭配 mask 就可以滿足大部分的場景。不過,如果漸層是 icon 內部填色的話該怎麼辦,或者 icon 互動樣式是實心邊框搭配漸層底色呢?

秉持優雅開發的信念,讓我們開始吧!
之前遇過一個超多漸層色的專案,就有用 CSS 做出漸層按鈕,像是這個 漸層超多的按鈕,的確做得出來。但是製作過程中發現有些侷限。
從範例中可以看到,CSS 能做到:
background:linear-gradient(...)
background 可以疊多層的特性。上層純色畫到 padding-box;下層漸層畫到 border-box。再把邊框設成 transparent,露出底下的漸層。
border: 2px solid transparent;
background: linear-gradient(#fff, #fff) padding-box,
linear-gradient(...) border-box;
background-image: linear-gradient(...);
color: transparent;
background-clip: text;
mask 遮罩。遮罩不透明的地方(線條)會顯示漸層,其他地方隱藏。
background:linear-gradient(...);
mask: url("data:image/svg+xml,...") center/contain no-repeat;
不難看出 CSS 漸層是由背景漸層出發的變體,color、border-color 這類只接受顏色的屬性,不接受漸層。而有形狀的漸層其實是用圖片或文字裁切出來的,所以除了替換底圖漸層外,很難再做更多變化。
先來介紹該怎麼再 SVG 中產生漸層。
沿用昨天的星星範例,我們可以內部新增一個 <defs> 標籤,利用 <linearGradient> 或 <radialGradient>定義漸層的 id 與座標。如此一來,就能在圖形 fill 與 stroke 設定 url(#id名稱) 引用漸層。
<defs>:用來儲存不直接顯示的元素,例如這次示範的漸層。<linearGradient>:建立線性漸層,必須設定id 且不可重複。預設水平漸變,或者用 x1, y1, x2, y2 設定劃出一條線,來指定漸變方向。<radialGradient>:建立放射性漸層,必須設定id 且不可重複。
cx, cy:漸變的圓心座標,與 r 一同決定漸變範圍。r:半徑。fx, fy:焦點座標,也就是漸變中心點。<stop> :定義漸層中間色的顏色(stop-color)、位置(offset)、透明度(stop-opacity)。<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
<defs>
<linearGradient id="star-line-gradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#ffe14d" />
<stop offset="100%" stop-color="#ff8a00" />
</linearGradient>
<radialGradient id="star-gradient" cx="50%" cy="45%" r="65%">
<stop offset="0%" stop-color="#ffe14d" />
<stop offset="100%" stop-color="#ff8a00" />
</radialGradient>
</defs>
<!-- 星星 -->
<path
class="star-shape"
d="M96.01 ... Z"
fill="url(#star-gradient)"
stroke="url(#star-line-gradient)"
stroke-width="4"
stroke-linejoin="round"
/>
<!-- 省略 -->
</svg>

多了漸層之後,星星看起來更有質感了!
現在要實作一個預設是灰框、hover 會填上漸層色、active 則變成深的漸層,類似按讚、愛心、收藏那類的按鈕 ,是一個可互動的 icon。
<button type="button" class="pure-icon-btn style-4">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
<defs>
<linearGradient id="gradient" cx="50%" cy="45%" r="65%">
<stop offset="0%" class="stop-start" />
<stop offset="100%" class="stop-end" />
</linearGradient>
</defs>
<!-- 星星 -->
<path
class="star-shape"
d="M96.01 ... Z"
fill="none"
stroke="currentColor"
stroke-width="4"
stroke-linejoin="round"
/>
<!-- 省略 -->
</svg>
基本架構差不多,但是漸層的 <stop> 分別下了 class 方便等一下控制漸層顏色。接下來就只需要用 CSS 來壓過預設樣式。
.style-4 {
--gradient-start-color: #ffe14d;
--gradient-end-color: #ff8a00;
color: gray;
.stop-start {
stop-color: var(--gradient-start-color);
}
.stop-end {
stop-color: var(--gradient-end-color);
}
}
.style-4:hover, .style-4:active{
color: #dcdcdc;
.star-shape {
fill: url(#gradient);
}
}
.style-4:active {
--gradient-start-color: #ff8a00;
--gradient-end-color: #b34700;
}

從上面的範例,我們還可以知道 currentColor 跟 url(#gradient) 是兩套不同機制:currentColor 走的是 CSS color 的繼承鏈,只能是純色;漸層走的是 url(#id) 引用,互不相關。