為什麼要導入 SVG & SVG Sprite
- 瀏覽器因圖片縮放比例,圖片會呈現模糊失針問題,產生馬賽克。
- 一堆小 ICON 載入,每個很小的圖片,卻分開去請求,造成伺服器的壓力,同時減少 request 數量,優關網站存取速度。
了解什麼是 SVG
透過文字編輯器打開 SVG 圖檔 ,我們會發文件裡裡存放圖片的路徑顏色,結構很像Html,是由 TAG 和 Attribute 組成,因此同相的圖樣放大幾倍都不會影響圖片的尺寸大小。
優缺點
優點
- 無失針,向量圖,支援縮放,放大不會鋸齒狀
- 圖片文字可編輯複製
- 可透過 css 修改 svg 圖檔顏色
缺點
- 一樣的圖檔,大小稍大。 ( 因此適合用在簡單的 Icon )
- 舊瀏覽器不支援。 ex : IE 11
SVG Sprite 在網站的載入方法
1.方法一 - 將多張圖拼在同一張,給予不同座標,透過 CSS 位置屬性來顯示。
.icon-match-event-3 {
width: 24px;
height: 24px;
zoom: 0.8;
background-position: -28px -4px;
background-repeat: no-repeat;
background-image: url(~@/assets/images/icon/match-event/match-event.svg);
}
2.方法二 - 將多張SVG 圖的路徑內容併在同個 SVG 中,並渲染在 HTML 中,並透過 :xlink:href=#targetId 來切換顯示內容。
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="`#${svgId}`" />
</svg>
SVG 在前端開發上特別的特性
1.SVG 在入載入時,CSS 的 Display 預設 none,不會顯示,需要額外給 CSS Display,才會顯示在頁面中。MDN SVG 說明
2. 在縮放時(Zoom) 會跳脫網頁排版,在瀏覽器除錯時,偵錯工具不會依據縮放的大小來顯示大小。
3. SVG 圖檔是可以透過文字檔開啟來編輯,結構如同 html。
4.壓縮 svg 大小
- 一般在繪圖工具所產生的 svg 圖檔,會額外產生用不到的 svg 屬性,這些屬性一多,也會影響圖檔的大小,這邊可以透過 webkapck plugin 移除一些不需要的屬性。
ex:vue-svgo-loader
在 VUE 框架中,簡化載入 SVG
為了像 icon font 一樣使用方便,我們得透過 svg loader
安裝
npm install svg-sprite-loader --save-dev
npm install svgo svgo-loader --save-dev
調整 Vue.config
chainWebpack: (config) => {
config.module
.rule('svg')
.exclude.add(resolve('src/assets/images/svg-icon'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/images/svg-icon'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]',
extract: true,
outputPath: 'static/img/',
publicPath: 'static/img/',
spriteFilename: 'main.svg'
})
.end()
.use('svgo-loader') // 最佳化 svg (優化寫法及移除不需要的 attibute , 約可以減少30% 以上的圖檔大小)
.loader('svgo-loader')
.end()
config.plugin('svg-sprite') // extract: true 才需要
.use(require('svg-sprite-loader/plugin'))
}
撰寫 Vue SVGIcon Component 元件
<template>
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="`#icon-${iconName}`" />
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconName: {
type: String,
default: '',
required: false
}
},
data: function() {
return {
}
},
computed: {
svgClass() {
if (this.iconClass) {
return 'svg-icon ' + 'icon-' + this.iconClass
} else {
return 'svg-icon'
}
}
}
}
</script>
<style>
.svg-icon {
display: inline-block;
overflow: hidden;
width: 32px;
height: 32px;
fill: currentColor;
}
</style>
在 App component 元件 中載入 main.svg
<template>
<div>
<Layout id="app" />
<span v-if="htmlSvgString.length" v-once id="mainSvg" v-html="htmlSvgString" />
</div>
</template>
<script>
import Layout from '@/views/layout'
export default {
components: { Layout },
data: function() {
return {
htmlSvgString: ''
}
},
created() {
const that = this
fetch('./static/images/main.svg')
.then(r => r.text())
.then(text => {
that.htmlSvgString = text
})
}
}
</script>
<style lang="scss">
#mainSvg {
position: absolute;
width: 0;
height: 0;
svg {
position: absolute;
width: 0;
height: 0;
}
}
// 如果要改色,要指定id,原本的顏色會掉,會吃父層的顏色
#icon-dropdown_b {
path {
fill: currentColor;
}
}
</style>
在 vue 全域註冊 ( main.js )
import SvgIcon from '@/components/SvgIcon'
Vue.component('Icon', SvgIcon)
// 引入至 web pack
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('@/assets/images/svg-icon', true, /\.svg$/)
requireAll(req)
將 SVG 圖檔放進 svg-icon
頁面使用方式
// icon-name 填入 icon 的檔案名稱
<SvgIcon :icon-name="getIconFileName(tab)" class="tab-icon" />
補充
- 如果改不動svg 顏色,檢查下層的 path 是不是有顏色,需要改成 currentColor
#icon-dropdown_b { path { fill: currentColor; } }
- 依據子資料夾去分類打包成一個 SVG Sprite,可以參考這篇 Generating Multiple Sprites
- iCon font,只有單色,可以透過icomoon網站上傳 svg 製作。
- Windows 檔案總管在管理 svg 圖時,無法預覽,裝 svg-explorer-extension 這個可以預覽下載連結