[Front-End General] SVG まわりの状況と、SVGO によるファイル最適化

現在の状況について調べたら、既に SVG は実用レベルなのかもと思った。

SVG って、どんなものでしたっけ。

仕様、そして職人芸。すごい。

実践するにはという考察。

mod_rewrite を使って、非対応ブラウザには png を表示させる。

実務で svg 扱えるようになっていたのかも。
使ってるよ、という方の話も聞いてみたい。

Contents

インストール

% npm install -g svgo

つかいかた

下記の SVGファイルで試します。

pitr_Rocket_icon.svg.thumb

元のSVGファイル

pitr_Rocket_icon.svg
中身は、4465 バイトの xml ファイルです。

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 13.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0"
     id="rocket_x28__x29__x3B_" inkscape:output_extension="org.inkscape.output.svg.inkscape" inkscape:export-filename="C:¥joanna¥Gfx¥drawings_vector¥nature_plants¥fruits¥papa_rocket.png" inkscape:export-xdpi="90" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" sodipodi:version="0.32" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" sodipodi:docname="papapishu_rocket.svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" sodipodi:docbase="D:¥Documents and Settings¥Joanna¥My Documents¥My Pictures¥graph_vector¥fruits" xmlns:svg="http://www.w3.org/2000/svg" inkscape:version="0.46" inkscape:export-ydpi="90"
     xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="128px" height="128px"
     viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve">
<defs>
        <inkscape:perspective  id="perspective4876" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_x="0 : 186.64798 : 1" sodipodi:type="inkscape:persp3d" inkscape:vp_z="559.62469 : 186.64798 : 1" inkscape:persp3d-origin="279.81235 : 124.43199 : 1">
        </inkscape:perspective>
</defs>
<sodipodi:namedview  id="base" borderlayer="true" showgrid="true" inkscape:window-y="22" inkscape:window-x="0" inkscape:window-height="744" inkscape:window-width="1280" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:cy="73.97559" inkscape:cx="58.84144" inkscape:zoom="2.9775825" inkscape:pageshadow="2" inkscape:pageopacity="0.0" objecttolerance="10" guidetolerance="10" gridtolerance="3" borderopacity="1.0" bordercolor="#666666" pagecolor="#ffffff">
    <inkscape:grid  type="xygrid" enabled="true" visible="true" id="grid3299" spacingy="4px" spacingx="4px"></inkscape:grid>
</sodipodi:namedview>
<g id="layer1" transform="translate(-66.38047,-391.3222)" inkscape:groupmode="layer" inkscape:label="Layer 1">
    <path id="path3297" sodipodi:nodetypes="cccc" fill="#FFFF00" stroke="#000000" stroke-width="6" stroke-linejoin="round" d="
        M93.613,471.512l23.289,22.551c29.936-25.092,68.019-46.946,70.099-95.696C138.343,402.017,116.761,440.12,93.613,471.512z"/>
        <path id="path3301" sodipodi:ry="8.6913204" sodipodi:rx="8.5918207" sodipodi:cy="36.691319" sodipodi:cx="60.59182" sodipodi:type="arc" fill="#008080" stroke="#000000" stroke-width="3.6104" stroke-linejoin="round" d="
        M172.173,423.465c-2.773,2.866-7.319,2.968-10.153,0.227c-2.833-2.742-2.883-7.288-0.109-10.154
        c0.001-0.002,0.003-0.003,0.005-0.005c2.773-2.867,7.318-2.968,10.152-0.227s2.883,7.288,0.109,10.154
        C172.175,423.461,172.174,423.463,172.173,423.465z"/>
        <path id="path3303" sodipodi:ry="8.6913204" sodipodi:rx="8.5918207" sodipodi:cy="36.691319" sodipodi:cx="60.59182" sodipodi:type="arc" fill="#008080" stroke="#000000" stroke-width="3.6104" stroke-linejoin="round" d="
        M158.002,438.1c-2.773,2.867-7.318,2.968-10.152,0.227c-2.834-2.741-2.883-7.288-0.109-10.154c0.002-0.001,0.003-0.003,0.004-0.004
        c2.773-2.867,7.319-2.968,10.152-0.227c2.834,2.741,2.884,7.288,0.11,10.154C158.005,438.097,158.004,438.098,158.002,438.1z"/>
        <path id="path3305" sodipodi:ry="8.6913204" sodipodi:rx="8.5918207" sodipodi:cy="36.691319" sodipodi:cx="60.59182" sodipodi:type="arc" fill="#008080" stroke="#000000" stroke-width="3.6104" stroke-linejoin="round" d="
        M143.636,452.935c-2.772,2.866-7.318,2.968-10.152,0.227c-2.833-2.742-2.882-7.288-0.109-10.154
        c0.002-0.002,0.003-0.003,0.005-0.005c2.772-2.867,7.318-2.968,10.152-0.227c2.834,2.741,2.883,7.288,0.11,10.154
        C143.64,452.932,143.638,452.934,143.636,452.935z"/>
    <path id="path3307" sodipodi:nodetypes="ccscc" fill="#FF0000" stroke="#000000" stroke-width="6" stroke-linejoin="round" d="
        M93.613,471.512L73.84,478.37c4.276-12.679,11.044-29.07,20.176-34.669c6-3.679,20.325-0.938,20.325-0.938L93.613,471.512z"/>
    <path id="path3309" sodipodi:nodetypes="ccscc" fill="#FF0000" stroke="#000000" stroke-width="6" stroke-linejoin="round" d="
        M117.612,493.328l-6.217,19.984c12.535-4.683,28.699-11.975,34.001-21.283c3.484-6.115,0.283-20.344,0.283-20.344L117.612,493.328z
        "/>
</g>
</svg>

実行結果

% svgo pitr_Rocket_icon.svg pitr_Rocket_icon.min.svg
Done in 152 ms!
4.36 KiB - 71.8% = 1.228 KiB
  • 1257 pitr_Rocket_icon.min.svg
  • 4465 pitr_Rocket_icon.svg

pitr_Rocket_icon.min.svg は、こんなにスッキリしている。

<svg version="1" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><g stroke="#000" stroke-linejoin="round"><path fill="#ff0" stroke-width="6" d="M27.233 80.19l23.289 22.551c29.936-25.092 68.019-46.946 70.099-95.696-48.658 3.65-70.24 41.753-93.388 73.145z"/><path fill="#008080" stroke-width="3.61" d="M105.793 32.143c-2.773 2.866-7.319 2.968-10.153.227-2.833-2.742-2.883-7.288-.109-10.154l.005-.005c2.773-2.867 7.318-2.968 10.152-.227s2.883 7.288.109 10.154l-.004.005z"/><path fill="#008080" stroke-width="3.61" d="M91.622 46.778c-2.773 2.867-7.318 2.968-10.152.227-2.834-2.741-2.883-7.288-.109-10.154l.004-.004c2.773-2.867 7.319-2.968 10.152-.227 2.834 2.741 2.884 7.288.11 10.154l-.005.004z"/><path fill="#008080" stroke-width="3.61" d="M77.256 61.613c-2.772 2.866-7.318 2.968-10.152.227-2.833-2.742-2.882-7.288-.109-10.154l.005-.005c2.772-2.867 7.318-2.968 10.152-.227 2.834 2.741 2.883 7.288.11 10.154l-.006.005z"/><path fill="#f00" stroke-width="6" d="M27.233 80.19l-19.773 6.858c4.276-12.679 11.044-29.07 20.176-34.669 6-3.679 20.325-.938 20.325-.938l-20.728 28.749z"/><path fill="#f00" stroke-width="6" d="M51.232 102.006l-6.217 19.984c12.535-4.683 28.699-11.975 34.001-21.283 3.484-6.115.283-20.344.283-20.344l-28.067 21.643z"/></g></svg>

gzip 圧縮で svgz

ちなみに gzip 圧縮すると、このようなサイズになりました。

% svgo pitr_Rocket_icon.svg -o - | gzip -cfq9 > pitr_Rocket_icon.svgz
  • 528 pitr_Rocket_icon.svgz

png だとどれくらい?

なお、png を ImageOptim で最適化すると、こんなサイズ。

  • 2924 pitr_Rocket_icon.svg.thumb.png

出力されたファイルの比較サンプル

サンプル画像にリンクを張ってあります。

Formatbyte
.png2924
.svg4465
.min.svg1257
.svgz528

Grunt

gzip圧縮したSVGファイル(.svgz)を表示するには

Apache の設定が必要になります。
今回確認のために実行した手順を記載しておきます。

.htaccess

画像フォルダに、下記の .htaccess ファイルを用意する。

AddType image/svg+xml svg svgz
AddEncoding gzip svgz

確認方法

Chrome Developer Tools などで確認します。

Response Header に下記の2つが含まれているか確認します。

  • Content-Type: image/svg+xml
  • Content-Encoding: gzip

.svg の場合

Accept-Ranges:bytes
Connection:Keep-Alive
Content-Length:4465
Content-Type:image/svg+xml
Date:Wed, 11 Dec 2013 18:24:27 GMT
ETag:"23aa3b-1171-4ed45c2927b51"
Keep-Alive:timeout=3, max=50
Last-Modified:Wed, 11 Dec 2013 17:42:59 GMT
Server:Apache
X-Content-Type-Options:nosniff
X-XSS-Protection:1; mode=block

.svgz の場合

Accept-Ranges:bytes
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:528
Content-Type:image/svg+xml
Date:Wed, 11 Dec 2013 18:30:33 GMT
ETag:"23aa3d-210-4ed45c29482d7"
Keep-Alive:timeout=3, max=50
Last-Modified:Wed, 11 Dec 2013 17:42:59 GMT
Server:Apache
X-Content-Type-Options:nosniff
X-XSS-Protection:1; mode=block