為什麼還要學 Image Sprites#
打開 DevTools 觀察 Network,會發現一個視覺單純的網站可能還是發了好幾個圖片請求。每張小 icon 都是一次 HTTP request,圖一多,瀏覽器與網路的成本就會跟著上升。
Image Sprites 的想法很直接:把多張小圖「拼」成一張大圖,瀏覽器只發一次請求,前端再透過 CSS 把需要的那一塊「裁」出來顯示。中文有時稱作「雪碧圖」。
依照圖片格式,Sprites 又分成兩種主流做法:
- 點陣圖的 CSS Sprites:處理 GIF、JPEG、PNG。
- SVG Sprites:處理向量圖。
兩者底層概念相同,都是用「合併請求」換取效能。
CSS Sprites(點陣圖)#
原理:用 background-position 定位#
CSS Sprites 並不是真的把大圖切開,而是讓多個元素都使用同一張背景圖,再透過 background-position 顯示不同區塊。看 W3C 範例最直接:
#home {
width: 46px;
height: 44px;
background: url(img_navsprites.gif) 0 0;
}
#next {
width: 43px;
height: 44px;
background: url(img_navsprites.gif) -91px 0;
}兩個元素引用同一張 img_navsprites.gif,靠不同 background-position 顯示不同 icon。
用工具產生 Sprites 與 CSS#
不需要自己手動拼圖計算座標。線上工具如 CSS Sprites Generator ↗、Toptal 的工具都能上傳多張圖後直接產生:
- 一張合併好的 sprite sheet。
- 對應的 CSS 程式碼,含每個區塊的
background-position。
範例使用方式如下:
<div class="sprite sprite-github"></div>
<div class="sprite sprite-gmail"></div>
<div class="sprite sprite-linkedin"></div>.sprite {
background-image: url(spritesheet.png);
background-repeat: no-repeat;
display: block;
}
.sprite-github {
width: 30px;
height: 30px;
background-position: -5px -5px;
}
.sprite-gmail {
width: 30px;
height: 30px;
background-position: -45px -5px;
}DevTools 觀察 Network 時,會看到只有一張 sprite sheet 被下載,後續的 icon 全部從同一張圖切割呈現,並且這張圖也會被瀏覽器快取。
SVG Sprites#
SVG 的 Sprites 雖然原理一樣是「合併請求」,但實作方式不同:透過 <symbol> 與 <use> 引用即可,不必計算座標。
製作 sprite.svg#
可以用 svgsprit.es
↗ 等服務上傳多張 SVG,產生一份合併檔案,存成 sprite.svg。檔案結構大致如下:
<svg width="0" height="0">
<symbol id="icon-a" viewBox="0 0 24 24">...</symbol>
<symbol id="icon-b" viewBox="0 0 24 24">...</symbol>
</svg>width 與 height 為 0,所以這段標籤本身不會顯示任何東西。
在 HTML 中引用#
<svg class="icon"><use xlink:href="sprite.svg#icon-a" /></svg>
<svg class="icon"><use xlink:href="sprite.svg#icon-b" /></svg>xlink:href 指向 sprite 檔案,井字號後接 <symbol> 的 id,瀏覽器就會插入對應的圖示。再配上 CSS 控制大小:
.icon {
width: 50px;
height: 50px;
margin: 0.5em;
}對比 CSS Sprites#
SVG Sprites 的優勢相當明顯:
- 用 id 定位,不必算座標。
- 可以透過
fill等 CSS 屬性動態改變顏色。 - sprite 拆成獨立檔案後可以被瀏覽器快取,也方便維護。
- 配合 React 等框架,可以包成元件統一管理。
進一步優化#
- 在合併之前,先用 SVGOMG 或 svgo 等工具把每張 SVG 最佳化(移除多餘屬性、視需求拔掉
fill以便之後用 CSS 改色)。 - 用 gulp、Webpack 等自動化工具串起「最佳化 ➡️ 合併」流程,例如
gulp-svgo加gulp-svg-sprite。
適用場景與限制#
Sprites 的核心 trade-off 是:用單一請求的「體積增加」換取「請求數量減少」。所以不是只要有多張圖都該用 Sprites。
判斷時可以用 200 KB 作為粗略分水嶺:以目前的瀏覽器與網路條件,圖片在這個大小以內載入時間差異不大,超過這個量級,合併大圖反而成為瓶頸。
實務上比較適合用 Sprites 的場景:
- 主選單、導覽列上的多個 icon。
- 贊助商或合作夥伴的 Logo 牆。
- 需要保留 hover、focus 等多個狀態的 icon(同一張圖可同時包含多狀態)。
不適合的場景:
- 經常新增、刪除的圖片(每次都要重新產生 sprite sheet)。
- 需要做響應式圖片的素材(不同尺寸都要再拼一次)。
- 寬高差異很大的圖(會讓佈局相當麻煩)。
CSS Sprites 中如果小圖大小不一致,背景區塊很容易互相影響,這也是它在現代專案中比較難維護的原因。
Sprites 過時了嗎?#
隨著 HTTP/2 普及(同連線多路請求成本大幅下降)、網路速度提升、SVG 相關工具鏈進步,Sprites 已經不像以前那麼必要。但「漸進淘汰」與「立即消失」是兩回事——許多既有網站仍在使用,淘寶這類大型站點至今也還能看到 sprite 的身影。理解這個技術,至少能維護舊系統,也能從中體會請求與資源大小之間的權衡。
小結#
Image Sprites 把「多圖多請求」變成「一圖一請求」,是減少網路請求的經典手段。CSS Sprites 適合處理點陣圖,SVG Sprites 在當代更為實用,搭配元件化開發更好維護。實際使用時要記得衡量大圖體積與維護成本,避免為了優化反而變成負擔。