様々なwebサイトのデザインを見ると、アイコンをSVGで制作する場合はとても多いです。
SVGを実際にブラウザで表示させるためにはいくつか方法が存在しますが、その中でもSVGコードをcssのbackground-imageに設定して表示させる方法が管理が簡単でおすすめです。
そのやり方を解説します。
まずは一般的なimgタグを使って、通常の画像のように表示する方法の問題点を見てみましょう。
一般的な方法で実装する問題点
結論から言うとimgタグを使って画像として読み込む方法の問題点は色の変更が容易ではない事です。
例えばこのような動きのデザインを実装したいとします。
こちらの動きをimgタグで読み込んだSVG画像を使用して制作する場合、以下のようなコードになります。
html
<i class="i-icon-wrap"> <img class="i-icon-phone -white" src="アイコンまでのパス(白色)"> <img class="i-icon-phone -blue" src="アイコンまでのパス(青色)"> </i>
scss
.i-icon-phone { &.-white { display: block; &:hover { display: none; } } &.-blue { display: none; &:hover { display: block; } } }
白と青のアイコンを用意し、cssでdisplay:noneで消したり表示したり。
この方法でも実装できますが、これだと、無駄に2つのアイコンを読み込むことになってしまします。
さらに、今は白と青の2つの色の準備で済みますが、他の色も追加したいとなった場合、デザインツールで色を変更し、SVGで書き出して、画像をアップしなおし、パスも変更すると、かなり運用や管理が面倒になってきます。
background-imageとしてurlを記載し、読み込む方法も同じです。
インライン化してcssから読み込むと楽になる
上記の問題を解決するにはSVG画像を画像として管理するのではなく、cssにコードを埋め込んで管理するのが最善です。
scssに以下のコードを記載しましょう。
@function str-replace($string, $search, $replace: '') { $index: str-index($string, $search); @if $index { @return str-slice($string, 1, $index - 1) + $replace + str-replace( str-slice($string, $index + str-length($search)), $search, $replace ); } @return $string; } @function url-encode($string) { $map: ( '%': '%25', '<': '%3C', '>': '%3E', ' ': '%20', '!': '%21', '*': '%2A', "'": '%27', '"': '%22', '(': '%28', ')': '%29', ';': '%3B', ':': '%3A', '@': '%40', '&': '%26', '=': '%3D', '+': '%2B', '$': '%24', ',': '%2C', '/': '%2F', '?': '%3F', '#': '%23', '[': '%5B', ']': '%5D' ); $new: $string; @each $search, $replace in $map { $new: str-replace($new, $search, $replace); } @return $new; } @function inline-svg($string) { @return url('data:image/svg+xml;charset=utf8,#{url-encode($string)}'); } @mixin phoneIcon($color) { background: { repeat: no-repeat; position: 50% 50%; size: cover; }; background-image: inline-svg( '' ); } @mixin tabicon($color) { background: { repeat: no-repeat; position: 50% 50%; size: cover; }; background-image: inline-svg( '' ); }
SVGはhtmlのようなコードで制作されています。
SVG画像をVS Cordで開きコードをinline-svg(”)ないに記載します。
たまに日本語が含まれていることがありますが、その場合は日本語を消してください。エラーの原因になります。
@mixin phoneIcon($color) { background: { repeat: no-repeat; position: 50% 50%; size: cover; }; background-image: inline-svg( '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="17.656"><path d="M1.966 11.18c3.271 6.235 6.945 6.877 8.013 6.317l.279-.146-2.5-4.77-.279.145c-.861.452-1.722-.854-2.824-2.955s-1.688-3.551-.826-4l.278-.147-2.5-4.77L1.328 1c-1.073.556-2.633 3.945.638 10.18zm9.805 5.377c.413-.217.186-.691-.049-1.138l-1.681-3.2c-.181-.344-.48-.539-.721-.412-.152.08-.5.247-.959.473l2.5 4.76zM5.634 4.775c.241-.126.251-.484.07-.828L4.026.738c-.235-.448-.5-.9-.909-.687L2.204.53l2.5 4.761c.439-.242.778-.437.93-.516z" fill="#{$color}"/> </svg>' ); } @mixin tabIcon($color) { background: { repeat: no-repeat; position: 50% 50%; size: cover; }; background-image: inline-svg( '<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8"><g fill="none"><path d="M0 8V2h6v6zm7-2V1H2V0h6v6z"/><path d="M5 7V3H1v4h4m1 1H0V2h6v6zm2-2H7V1H2V0h6v6z" fill="#{$color}"/></g></svg>' ); }
fill=””の部分で色の設定を行っていますので、こちらに引数を渡します。
fillを複数持っているSVGもあるので、その場合は全てのfillに引数を渡します。
渡す引数は同じでなくても大丈夫です。 例えば以下のように場所によって別の値を渡す事も可能です。
@mixin tabIcon($color1, $color2) { background: { repeat: no-repeat; position: 50% 50%; size: cover; }; background-image: inline-svg( '<g> <svg fill="#{$color1}"/></svg> <svg fill="#{$color2}"/></svg> </g>' ); }
使い方
mixinから定義する事によって以下のようにcssから簡単に表示する事ができるようになります。
html
<i class="i-icon-phone"></i>
scss
.i-icon-phone { width: 10px; height: 15px; @include phoneIcon(#1571DA); a:hover & { @include phoneIcon(#fff); } }
- 画像を2回読み込む必要がなく、通信量を落せる
- パスの変更などに影響を受けない
- 引数から色情報を渡すだけで全ての色のパターンを表示可能
など、大きなメリットがあります。
@function部分について
@functionはSVGをbase64エンコーディングする関数を記載しています。
@funciton部分はfoundation/_function.scssなどに切り出して定義しておくといいかと思います。
参考:身につけておきたいWebサイト高速化テクニック #5|リクエスト数削減テクニック01:インラインイメージ編