iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
Modern Web

從實務需求出發:前端視覺與 UI 互動開發實踐系列 第 8 篇

【Day 08】 SVG 實作:是漸層,我加了漸層

  • 分享至 

  • xImage
  •  

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

https://ithelp.ithome.com.tw/upload/images/20260923/20184345j2fHm7Eexz.png

秉持優雅開發的信念,讓我們開始吧!

純 CSS 的限制

之前遇過一個超多漸層色的專案,就有用 CSS 做出漸層按鈕,像是這個 漸層超多的按鈕,的確做得出來。但是製作過程中發現有些侷限。

特性分析

從範例中可以看到,CSS 能做到:

  1. 色塊漸層:background:linear-gradient(...)
  2. 邊框漸層:利用 background 可以疊多層的特性。上層純色畫到 padding-box;下層漸層畫到 border-box。再把邊框設成 transparent,露出底下的漸層。
     border: 2px solid transparent;
     background: linear-gradient(#fff, #fff) padding-box,
             linear-gradient(...) border-box;
    
  3. 文字漸層:把背景裁切成文字的形狀,再把文字顏色設成透明,就能透出底下的漸層。
     background-image: linear-gradient(...);
     color: transparent;
     background-clip: text;
    
  4. 圖示漸層:在元素本身填滿漸層,再用 SVG 當 mask 遮罩。遮罩不透明的地方(線條)會顯示漸層,其他地方隱藏。
       background:linear-gradient(...);
       mask: url("data:image/svg+xml,...") center/contain no-repeat;
    

不難看出 CSS 漸層是由背景漸層出發的變體,color、border-color 這類只接受顏色的屬性,不接受漸層。而有形狀的漸層其實是用圖片或文字裁切出來的,所以除了替換底圖漸層外,很難再做更多變化。


SVG 漸層

簡易範例

先來介紹該怎麼再 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>

https://ithelp.ithome.com.tw/upload/images/20260922/20184345GPs4N79biK.png

多了漸層之後,星星看起來更有質感了!

icon 按鈕

現在要實作一個預設是灰框、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) 引用,互不相關。


完整範例

Codepen 範例

參考資料


上一篇
【Day 07】SVG 實作:用 fill / stroke 告別海量 icon 靜態圖檔
下一篇
【Day 09】SVG 實作:化繁為簡,圖形元件化
系列文
從實務需求出發:前端視覺與 UI 互動開發實踐 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言