SVG 的使用

圖片來源:pixiv 38190692
SVG 圖標是矢量圖,能夠很方便的轉換顏色,修改文字,畫質無損進行縮放,並且文件很是小,相比一樣的 png 圖片,大小僅爲一成
SVG 經過可配置顏色和配置文字的方式,有效減小了圖標文件的個數。從而使設計師和前端工程師工做量都減小,還能提高了加載速度javascript

更新於 2018.7.29
首發於夏味的博客: xiaweiss.comphp

介紹

說到性能優化,常見的一種方式就是壓縮圖片,一般圖片最多壓縮到原文件的 50%。並且若是一個圖標有 7 種顏色呢?那麼設計就得給出 7 種顏色的圖片,前端代碼也得引用不一樣的 7 個路徑。。。想一想都以爲複雜。css

SVG 圖完美地解決了這一痛點,大小僅爲原文件 10% 左右。還能夠經過改寫代碼來任意改變顏色,甚至支持在代碼中動態地傳入顏色。動態地傳入顏色時,即使有 1萬種顏色,也僅僅一個文件。html

而生成 SVG 文件也很是簡單,設計師可使用 矢量圖 繪圖軟件直接導出 svg 格式的文件,如 Adobe Illustrator(簡稱 AI)、sketch前端

固然對於 Adobe Photoshop 中繪製的圖片,手工轉換矢量圖比較困難耗時,在線工具解決了這一難題java

其中目前免費在線轉換工具裏,這款是最好的 https://www.vectorizer.io/node

轉換後,可能會有一些冗餘的代碼,可使用命令行工具 svgo 進行批量壓縮。固然若是文件數量很少,直接使用在線工具 https://jakearchibald.github.io/svgomg/ 便可。react

這些個 SVG 壓縮工具只是靜態工具,不會被上傳到網絡上去,不須要擔憂被盜圖,有興趣的同窗能夠研究下源碼,以及那個web 壓縮工具的源碼css3

SVG 圖標示例

首先 svg 在瀏覽器裏和手機上,與圖片同樣的,能夠正常顯示出來 下面這個就是一個完整的 SVG 圖,包括文字git

xiaweiss.com/images/2018…

下面將它改寫爲爲 400px 寬度的 SVG 圖,仍然能夠看到很清晰

xiaweiss.com/images/2018…

接下來,使用微信屏幕截圖,看看一樣 400px 寬度的 png 圖,而且使用智圖 壓縮圖片

接下來看看這三個文件的大小

能夠看出 SVG 圖能夠任意改變尺寸,不損失清晰度 相比 png 圖體積小不少的狀況下,仍然比 png 圖更清晰

接下來使用代碼編輯器打開 SVG 文件,能夠看到以下代碼

也許看到這一堆代碼要頭暈了。別擔憂,實際應用時,並不須要本身手寫 SVG 代碼,只是改改就足夠了 仔細看很相似前端經常使用的 html 標籤

<?xml version="1.0" encoding="UTF-8"?>
<svg width="60px" height="24px" viewBox="0 0 60 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <!-- Generator: Sketch 51 (57462) - http://www.bohemiancoding.com/sketch -->
    <title>按鈕/關注-紅色底</title>
    <desc>Created with Sketch.</desc>
    <defs></defs>
    <g id="按鈕/關注-紅色底" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <rect id="Rectangle-3" fill="#FF4C6A" x="0" y="0" width="60" height="24" rx="12"></rect>
        <g id="icon/關注加號" transform="translate(3.000000, 0.000000)">
            <g id="Group" stroke-width="1" transform="translate(8.000000, 8.000000)" fill="#FFFFFF">
                <path d="M3,3 L3,1 C3,0.44771525 3.44771525,1.01453063e-16 4,0 C4.55228475,-1.01453063e-16 5,0.44771525 5,1 L5,3 L7,3 C7.55228475,3 8,3.44771525 8,4 C8,4.55228475 7.55228475,5 7,5 L5,5 L5,7 C5,7.55228475 4.55228475,8 4,8 C3.44771525,8 3,7.55228475 3,7 L3,5 L1,5 C0.44771525,5 6.76353751e-17,4.55228475 0,4 C-6.76353751e-17,3.44771525 0.44771525,3 1,3 L3,3 Z" id="Combined-Shape"></path>
            </g>
            <rect id="Rectangle-10" fill="#D8D8D8" opacity="0" x="0" y="0" width="24" height="24"></rect>
        </g>
        <text id="哈哈" font-family="PingFangSC-Regular, PingFang SC" font-size="12" font-weight="normal" line-spacing="18" fill="#FFFFFF">
            <tspan x="24" y="16">哈哈</tspan>
        </text>
    </g>
</svg>
複製代碼

SVG 代碼說明

<svg width="60px" height="24px" viewBox="0 0 60 24" ... > ... </svg>
複製代碼

svg 標籤來控制寬高,width,height 是實際顯示的寬高,能夠修改成你想要顯示的大小 而 viewBox 裏的大小,則是原始大小,能夠理解爲畫紙的大小位置,其中左上角座標爲 0 0,右下角座標爲 60 24(方向分別爲 x, y)

<g id="Group" stroke-width="1" transform="translate(8.000000, 8.000000)" fill="#FFFFFF"> ... </g>
複製代碼

g 標籤表示分組,也就是繪圖軟件中的圖層。相似代碼中的繼承,它的屬性,若是子標籤裏沒有規定,就會使用它的屬性設置 例以下面這兩段代碼是一樣的效果

<g fill="#FF4C6A">
  <rect x="0" y="0" width="60" height="24" rx="12"></rect>
</g>
複製代碼
<g >
  <rect fill="#FF4C6A" x="0" y="0" width="60" height="24" rx="12"></rect>
</g>
複製代碼

path 表示線條, reat 表示方形,text 表示文字 代碼 d="M3,3 L3,1 ...' 是繪製線條的代碼,也稱做路徑(path)

fill 表示填充色,相似於 css 裏的背景色(background-color)

stroke 表示描邊,相似於 css 的邊框顏色(border-color)

因此修改色值時,只須要修改這兩個顏色便可 色值與 css 相同,可使用透明色 transparent,以及 rgba(0,0,0,0.5) 也能夠添加屬性 opacity='0.5' 來控制透明度,值爲 0 ~ 1

至於修改文字,找到對應的文字,直接替換便可

動態渲染 SVG

因爲最近正在作 react-native, SVG 的配置難度較大,就用它來示例一下

這裏使用 react-native-svg 庫來渲染 SVG 圖片

注意設計師導出 SVG 圖標前,請清除掉蒙層(mask)、顏色疊加和濾鏡(filter)、陰影(shadow),目前 react-native 是不支持的

首先使用 msvgc 庫來一鍵把 SVG 文件轉換爲 React 組件

nodejs 環境裏安裝 msvgc,源文件放置到 App/Svg/目錄下,配置腳本運行便可 導出的組件位於 ./App/Components/Svg/svg 目錄

"scripts": {
  "svg": "msvgc --react-native -f ./App/Svg/ -o ./App/Components/Svg  && standard --fix './App/Components/Svg/svg/*.js'"
}
複製代碼

再把修正屬性的語法,所有改成駝峯寫法,例如 fill-rule 改成 fillRule 修正後將文件移動到 App/Components/Svg(其餘目錄也昆蟲,由於每次新轉換時,會覆蓋App/Components/Svg/svg/ 目錄)

接下來,進一步修改代碼,就能夠經過組件的 props 值裏動態傳參了

import React from 'react'
import Svg, { G, Rect, Path, Text } from 'react-native-svg'
import { path } from 'ramda' // 根據鍵名取值,取不到或錯誤時,返回 undefined
// path([鍵名],被取值的對象)

const ButtonFollow = props => {
  const Color = {
    red: '#ff4c6a',
    grey: '#6c6c6c'
  }
  const fillColor = path([props.color], Color) || props.color || Color.red
  return (
    <Svg
      width={props.width || 60}
      height={props.height || 24}
      viewBox='0 0 60 24'>
      <G stroke='none' strokeWidth='1' fill='none' fillRule='evenodd'>
        <Rect fill={fillColor} x='0' y='0' width='60' height='24' rx='12' />
        <G strokeWidth='1' transform='translate(8, 8)' fill='#FFFFFF'>
          <Path d='M3,3 L3,1 C3,0.44771525 3.44771525,1.01453063e-16 4,0 C4.55228475,-1.01453063e-16 5,0.44771525 5,1 L5,3 L7,3 C7.55228475,3 8,3.44771525 8,4 C8,4.55228475 7.55228475,5 7,5 L5,5 L5,7 C5,7.55228475 4.55228475,8 4,8 C3.44771525,8 3,7.55228475 3,7 L3,5 L1,5 C0.44771525,5 6.76353751e-17,4.55228475 0,4 C-6.76353751e-17,3.44771525 0.44771525,3 1,3 L3,3 Z' />
        </G>
        <Text fontSize='12' lineSpacing='18' fill='#FFFFFF' x='24' y='16'>
          {props.text || '關注'}
        </Text>
      </G>
    </Svg>
  )
}

export default ButtonFollow
複製代碼

調用

<ButtonFollow width={300} height={120} color='red' />
<ButtonFollow /> 取默認值 64,24,默認色 red
<ButtonFollow width={300} height={120} color='#ccc' /> 任意顏色
複製代碼

react-art

(基於 react-naive 0.55.4 介紹)

facebook 自家也出品了一個庫 react-art,而且有 react-native-art,兩者大致上使用的同一套 API 它支持的元素標籤交少,例如沒有方形。但更簡潔,不須要引入額外庫 (react-native-svg 壓縮後大約 200KB)

相關語法能夠看 react-native-art-繪圖入門 瞭解一下 源碼位於 node_modules/react-native/Libraries/ART/ReactNativeART.js 缺點是尚未找到現成的轉換插件,須要手工轉換

首先來封裝一個方形組件,width、height 控制寬高,r 控制圓角半徑(border-radius)

import React from 'react'
import { ART } from 'react-native'

const { Shape } = ART

function extractNumber (value, defaultValue) {
  if (value == null) {
    return defaultValue
  }
  return +value
}

const RectART = props => {
  let w = extractNumber(props.width, 0)
  let h = extractNumber(props.height, 0)
  let r = extractNumber(props.r, 0)

  if (w === 0 || h === 0) return null

  if (r > 0) {
    h -= r * 2
    w -= r * 2
    return <Shape {...props}
      d={`M${r},0 h${w} a${r},${r} 0 0,1 ${r},${r} v${h} a${r},${r} 0 0,1 ${-r},${r} h${-w}  a${r},${r} 0 0,1 ${-r},${-r} v${-h} a${r},${r} 0 0,1 ${r},${-r} z`}
    />
  } else {
    return <Shape {...props} d={`h${w} v${h} h${-w} z`} />
  }
}

export default RectART
複製代碼

接下來轉換按鈕

  1. 將 svg 換爲 Surface,寬高爲顯示端寬高,不指定畫布大小
  2. Surface 內層寫上一層 Group ,添加屬性 scale 用於總體縮放,縮放倍數 X 基於畫布原始大小來計算
  3. g 轉換爲 Group, Group 裏的屬性只支持 fill 和 transform,其餘的都寫到子標籤裏去
  4. path 轉換爲 Shape,d 仍然是路徑,複製過來便可(react-art 內置了一套 svg 轉換器,源碼位於路徑 node_modules/art/core/path.js
  5. transform 轉換爲這種形式,注意 scale 要放在左邊,與 css3 相同還支持 rotate
transform = new Transform().scale(2).translate(2, 3)
複製代碼
  1. text 轉換爲 Text,直接包裹文字便可,

其中 font 指定字體格式(注意必須指定字體) (react-native 裏指定多個字體只有第一個字體生效)

font='normal 12 PingFangSC-Regular'
複製代碼

也能夠寫爲(注意必須指定字體)

font={fontFamily: 'PingFangSC-Regular',fontSize: '12'}
複製代碼

還有兩個屬性是 fontWeight、fontStyle

import React from 'react'
import { path } from 'ramda' // 根據鍵名取值,取不到或錯誤時,返回 undefined
// path([鍵名],被取值的對象)
import { ART, View } from 'react-native'
import Rect from './RectART.js'

const { Group, Shape, Surface, Transform, Text } = ART

const ButtonFollow = props => {
  const Color = {
    red: '#ff4c6a',
    grey: '#6c6c6c'
  }

  const fillColor = path([props.color], Color) || props.color || Color.red
  const X = (Math.min(props.width / 60, props.height / 24)) || 1

  return (
    <View style={props.style}>
      <Surface width={props.width || 60} height={props.height || 24} >
        <Group scale={X} >
          <Rect fill={fillColor} r='12' width='60' height='24' />
          <Shape fill='#FFFFFF' transform={new Transform().translate(8, 8)} d='M3,3 L3,1 C3,0.44771525 3.44771525,1.01453063e-16 4,0 C4.55228475,-1.01453063e-16 5,0.44771525 5,1 L5,3 L7,3 C7.55228475,3 8,3.44771525 8,4 C8,4.55228475 7.55228475,5 7,5 L5,5 L5,7 C5,7.55228475 4.55228475,8 4,8 C3.44771525,8 3,7.55228475 3,7 L3,5 L1,5 C0.44771525,5 6.76353751e-17,4.55228475 0,4 C-6.76353751e-17,3.44771525 0.44771525,3 1,3 L3,3 Z' />
          <Text font={'normal 12 PingFangSC-Regular'} fill='#FFF' transform={new Transform().translate(24, 4)}>
            {props.text || '關注'}
          </Text>
        </Group>
      </Surface>
    </View>
  )
}

export default ButtonFollow
複製代碼
<ButtonFollow width={300} height={120} />
複製代碼

react-native-art API

(基於 react-naive 0.55.4 介紹) 下面是我看了源碼以後羅列的 API,供參考使用

相關語法能夠看 react-native-art-繪圖入門 瞭解一下 源碼位於 node_modules/react-native/Libraries/ART/ReactNativeART.js

Surface

Property Type Description
width string
heigh string -

Group

Property Type Description
opacity number
scale number
scaleX number
scaleY number
transform transform
visible boolean false equals opacity 0

Shape

Property Type Description
d path
fill string Color
opacity number
scale number
scaleX number
scaleY number
strokeCap string butt, square, round(default)
strokeDash
strokeJoin string miter, bevel, round
strokeWidth number 1(default)
transform transform
visible boolean false equals opacity 0

Text

Property Type Description
alignment string right, center, left(default)
fill string Color
font string normal 10 PingFangSC-Regular
font object {fontFamily,fontSize,fontWeight,fontStyle}
opacity number
path path
scale number
scale number
scaleX number
scaleX number
scaleY number
scaleY number
strokeCap string butt, square, round(default)
strokeDash
strokeJoin string miter, bevel, round
strokeWidth number 1(default)
transform transform -

Transform

Property params Description
transform xx, yx, xy, yy, x, y
translate x, y
move x, y
moveTo x, y
scale x, y
scaleTo x, y
rotate deg, x, y
rotateTo deg, x, y
resizeTo width, height this.scaleTo(width / w, height / h)
point x, y
inversePoint x, y -

上面表格含 To 的都是絕對座標,例如 move 是相對座標,moveTo 是絕對座標

其餘存在但不經常使用的 API Path ClippingRectangle LinearGradient Pattern RadialGradient

SVG path 說明

具體能夠看 w3c 官方文檔 https://www.w3.org/TR/SVG2/paths.html 大寫字母都表明絕對座標 小寫字母都表明相對座標

下面這幾個寫法效果相同 M 10 20 M 15 25 v 5 M 10,20 M 15,25 v 5 M10,20 M15,25 v5 M10,20 15,25 v5 (與前一個字母相同時,字母能夠省略)

字母主要有如下幾種,能夠對應到上面的表格

Command Name Parameters Description
M moveto x, y 移動
L lineto x, y 畫線
H horizontal lineto x 畫水平線
V vertical lineto y 畫垂直線
A elliptical arc 橢圓
Z closepath 鏈接到起始點,只能在最後使用

橢圓 A 有6個參數 rx ry x-axis-rotation large-arc-flag sweep-flag x y 含義分別爲

Parameters Description
rx x 軸半徑
ry y 軸半徑
x-axis-rotation 相對於 x 軸的旋轉角度,例如 30 表示 30 度
large-arc-flag 1 繪製大圓,0 繪製小圓
sweep-flag 旋轉方式: 1 順時針,0 逆時針
x 結束點的 x 座標
y 結束點的 x 座標
相關文章
相關標籤/搜索