レスポンシブ対応クリッカブルマップも!?SVGでできること・便利な使い方

フロントエンド
エンジニア

T.K

全世界の皆様、
あけましておめでとうございます
そしてものすごくお久しぶりです( ^ω^)
フロントエンドエンジニアのT.Kです。

フロントエンド
エンジニア

T.K

前回記事から1年半以上も経ってしまいました・・・・
皆様体調お変わりありませんでしょうか?
私T.Kは本記事執筆時、1ヶ月ぐらい微熱が続いて大変でした・・・・
(自律神経失調症でした。皆様もお気をつけて・・・)

フロントエンド
エンジニア

T.K

すっかり体力も落ちてしまいましたが、焼肉を食べると体力のみならず精神もめちゃめちゃ回復しました。
やっぱり好きなものを食べることは人生において重要なことですね。

人生にも仕事にも遊びにも、何事にも重要なことというものはあるものです。

今回は昨今のウェブ制作において重要なものの一つである、SVGのお話。

簡単に様々なことができるSVGの便利な使い方を、一挙ご紹介!

 

そもそもSVGとは

Scalable Vector Graphics(スケーラブル・ベクター・グラフィックス、SVG、日: 変倍ベクタ図形[2][3])は、XMLベースの、2次元ベクターイメージ用の画像形式の1つである。アニメーションやユーザインタラクションもサポートしている。SVGの仕様はW3Cによって開発され、オープン標準として勧告されている。

出典 Scalable Vector Graphics – Wikipedia

SVGとは、PNGやJPEGと同様、画像形式の一つです。

SVGは他形式と異なり、

  • 拡大しても荒くならない
  • マークアップ形式で記述される
  • 画像の縦幅/横幅に画像容量が比例しない

という特徴があります。

拡大しても解像度が下がらない

PNGやJPEGはピクセルデータであるのに対し、SVGはベクターデータです。

ベクターデータは線や塗りつぶし等がテキストデータで記述されているため、拡大しても荒くなりません。

マークアップ形式で記述される

例えば下記のSVG画像(弊社ロジカルスタジオのロゴ画像)。

SVGをテキストエディタで開くと、このように表示されます。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="レイヤー_1" x="0px" y="0px" viewBox="0 0 322 54" style="enable-background:new 0 0 322 54;" xml:space="preserve">
<style type="text/css">
	.st0{fill:#818181;}
	.st1{fill:#EB008B;}
	.st2{fill:none;stroke:#FEFEFE;stroke-width:0.3098;stroke-miterlimit:10;}
	.st3{fill:none;}
	.st4{clip-path:url(#SVGID_1_);fill:#EB008B;}
	.st5{clip-path:url(#SVGID_2_);fill:none;stroke:#FEFEFE;stroke-width:0.3098;stroke-miterlimit:10;}
	.st6{clip-path:url(#SVGID_3_);fill:#EB008B;}
	.st7{clip-path:url(#SVGID_3_);fill:none;stroke:#FEFEFE;stroke-width:0.3098;stroke-miterlimit:10;}
	.st8{clip-path:url(#SVGID_4_);fill:#EB008B;}
	.st9{clip-path:url(#SVGID_5_);fill:none;stroke:#FEFEFE;stroke-width:0.3098;stroke-miterlimit:10;}
	.st10{clip-path:url(#SVGID_6_);fill:#EB008B;}
	.st11{clip-path:url(#SVGID_7_);fill:none;stroke:#FEFEFE;stroke-width:0.3098;stroke-miterlimit:10;}
	.st12{clip-path:url(#SVGID_8_);fill:#7A1D8F;}
  ~略~
</style>
<g>
	<g>
		<polygon class="st0" points="72.5,39.3 72.5,39.3 72.5,16.4 74.3,16.4 74.3,37.5 83.1,37.5 83.1,39.3   "/>
		<path class="st0" d="M96.1,39.7L96.1,39.7c-6.8,0-11.6-5-11.6-12.1c0-6.7,4.9-11.7,11.6-11.7s11.6,5,11.6,11.8    C107.7,34.7,102.8,39.7,96.1,39.7z M96.1,17.7L96.1,17.7c-5.6,0-9.7,4.3-9.7,10.2c0,5.6,4.2,10.1,9.7,10.1c5.5,0,9.7-4.5,9.7-10.2    C105.8,22.1,101.6,17.7,96.1,17.7z"/>
		<path class="st0" d="M122.7,39.7L122.7,39.7c-3.7,0-6.5-1.1-8.7-2.9c-2.4-2.2-3.8-5.4-3.8-9c0-7,5-11.8,12.3-11.8    c2.7,0,4.8,0.6,7.6,1.9l-0.7,1.9c-2.3-1.4-4.4-2-7-2c-6.1,0-10.3,4.1-10.3,10.1c0,6.2,4.2,10.2,10.8,10.2c2.1,0,3.9-0.3,5.8-1.1    v-7.8h-6.4v-1.8h8.2v10.8C127.7,39.3,125.4,39.7,122.7,39.7z"/>
		<polygon class="st0" points="135.9,16.4 135.9,16.4 137.8,16.4 137.8,39.3 135.9,39.3   "/>
		<path class="st0" d="M154.8,39.7L154.8,39.7c-7.1,0-12-4.9-12-11.9s4.9-11.9,11.8-11.9c2.5,0,4.5,0.6,6.7,1.9l-0.7,1.8    c-2-1.4-3.6-1.9-5.9-1.9c-5.8,0-10,4.2-10,10.1c0,6,4.2,10.2,10.2,10.2c2.6,0,4.4-0.5,6.5-1.9v2.1    C159.1,39.3,157.1,39.7,154.8,39.7z"/>
		<path class="st0" d="M181.5,39.3L181.5,39.3l-2.7-7.3h-10.7l-2.7,7.3h-2.1l8.8-22.9h2.5l8.9,22.9H181.5z M173.3,18L173.3,18    l-4.7,12.3h9.4L173.3,18z"/>
		<polygon class="st0" points="186.4,39.3 186.4,39.3 186.4,16.4 188.2,16.4 188.2,37.5 196.9,37.5 196.9,39.3   "/>
		<path class="st0" d="M213,39.5L213,39.5c-2.2,0-4.1-0.6-5.9-1.6l0.6-1.8c1.8,1.2,3.4,1.6,5.4,1.6c3.5,0,5.7-1.9,5.7-4.7    c0-1.2-0.3-2.3-1.1-3.1c-0.7-0.7-1.4-1.2-3.7-2c-2.1-0.7-3.1-1.2-4-1.9c-1.4-1.1-2.1-2.5-2.1-4.2c0-3.6,2.7-6.2,6.7-6.2    c1.6,0,3.2,0.5,4.8,1.3l-0.6,1.8c-1.5-1-2.7-1.3-4.2-1.3c-2.7,0-4.8,1.8-4.8,4.3c0,1.1,0.5,2,1,2.7c0.7,0.7,1.5,1,3.9,1.9    c2.5,0.9,3.8,1.8,4.7,2.7c0.9,1.1,1.4,2.5,1.4,4C220.7,36.9,217.6,39.5,213,39.5z"/>
		<polygon class="st0" points="232.2,17.9 232.2,17.9 232.2,39 230.2,39 230.2,17.9 222.4,17.9 222.4,16.1 240,16.1 240,17.9   "/>
		<path class="st0" d="M261,34.6L261,34.6c-1.2,3.2-4.1,4.8-8.5,4.8c-4.5,0-7.4-1.8-8.6-5.2c-0.5-1.3-0.7-3.1-0.7-5.2V16h1.8v12.9    c0,2.6,0.2,4.1,0.9,5.3c1,2.4,3.2,3.4,6.5,3.4c3.5,0,5.8-1.2,6.8-3.7c0.5-1.1,0.7-2.6,0.7-4.9V16.1h1.8v13    C261.8,31.4,261.6,33.4,261,34.6z"/>
		<path class="st0" d="M279.8,38L279.8,38c-1.6,0.7-3.2,1-5.7,1h-8.2V16.1h8.2c2.5,0,4.1,0.2,5.7,1c3.9,1.4,6.1,5.3,6.1,10.4    C285.8,32.8,283.7,36.7,279.8,38z M279,18.6L279,18.6c-1.4-0.5-2.9-0.7-4.9-0.7h-6.2v19.4h6.1c2.1,0,3.8-0.2,5.2-0.7    c3.1-1.3,4.9-4.6,4.9-9C284,23.2,282.2,19.8,279,18.6z"/>
		<polygon class="st0" points="290.6,16.1 290.6,16.1 292.7,16.1 292.7,39 290.6,39   "/>
		<path class="st0" d="M309,39.5L309,39.5c-6.8,0-11.6-5-11.6-12.1c0-6.7,4.9-11.7,11.6-11.7c6.7,0,11.6,5,11.6,11.9    C320.6,34.4,315.6,39.5,309,39.5z M309,17.4L309,17.4c-5.6,0-9.7,4.3-9.7,10.2c0,5.6,4.2,10.1,9.7,10.1c5.4,0,9.7-4.4,9.7-10.2    C318.7,21.9,314.3,17.4,309,17.4z"/>
	</g>
	<g>
		<polygon class="st1" points="31.9,27.5 31.9,27.5 37.3,23.7 37.3,16.1 31.9,19.9   "/>
		<polygon class="st2" points="31.9,27.5 31.9,27.5 37.3,23.7 37.3,16.1 31.9,19.9   "/>
		<polygon class="st1" points="48.2,31.3 48.2,31.3 53.7,27.5 53.7,19.9 48.2,23.7   "/>
		<polygon class="st2" points="48.2,31.3 48.2,31.3 53.7,27.5 53.7,19.9 48.2,23.7   "/>
		<polygon class="st1" points="48.2,38.9 48.2,38.9 53.7,35 53.7,27.5 48.2,31.3   "/>
		<polygon class="st2" points="48.2,38.9 48.2,38.9 53.7,35 53.7,27.5 48.2,31.3   "/>
		<polygon class="st1" points="48.2,46.4 48.2,46.4 53.7,42.6 53.7,35 48.2,38.9   "/>
		<polygon class="st2" points="48.2,46.4 48.2,46.4 53.7,42.6 53.7,35 48.2,38.9   "/>
		<polygon class="st1" points="48.2,54 48.2,54 53.7,50.2 53.7,42.6 48.2,46.4   "/>
		<polygon class="st2" points="48.2,54 48.2,54 53.7,50.2 53.7,42.6 48.2,46.4   "/>
		<rect class="st3" width="56.2" height="53.6"/><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="_x32_" x="0px" y="0px" viewBox="0 0 512 512" style="width: 256px; height: 256px; opacity: 1;" xml:space="preserve">

    ~略~

SVG画像は、このHTMLのようなマークアップで出来ています。

そのため、下記のようなことも可能。

  • ソースコードにSVGコードを直接表記して画像を表示
  • HTMLと同様、それぞれの要素にクラスを振ってCSSでスタイルを操作する

下記をご覧ください。<img>タグを書かずとも、画像を表示出来ています。

また:hoverにより、SVGの各要素にマウスをホバーさせると色が変わるようにしています。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

画像の縦幅/横幅に画像容量が比例しない

SVG以外の画像はピクセルの集合体であるため、画像の縦幅/横幅により画像容量が大きく左右されます。

それと比べ、SVG画像はテキストデータのため、縦幅/横幅によって画像容量があまり変わりません。

SVGのデメリット

このように便利なSVGですが、反面デメリットもあります。
それは、複雑な画像には向かないということ。
複雑な画像をSVGで実装しようとすると、テキストデータと言えど容量が莫大になってしまいます。

また、地味ですがWordPressにアップできないというのもデメリットかと思います。
当ロジカルスタジオブログはWordPressで実装されていますが、
この記事に記載しているSVG画像はテキストエディタにソース直打ちで表示しています
(WordPressにアップできない理由はセキュリティ面での配慮です)

ちなみに昔は「対応ブラウザが少ない」というデメリットもあったようですが、
2024年1月現在では大体のブラウザで使えます。やったね!!!!

SVGの使い所

では、SVGはどのようなところで使えばよいのでしょうか?
私は下記のような場合にSVGを使うことが多いです。

  • 比較的単純な画像の場合
  • 画像を拡大してもぼやけない必要がある場合
  • 画像の一部の要素を操作する必要がある場合

比較的単純な画像の場合

例えばアイコンや企業ロゴなど。
私はあまり複雑でない画像に関しては、SVGで実装しています。

画像を拡大してもぼやけない必要がある場合

例えば、スタンプ機能を実装するとき。
Twitter(現X)のスタンプ機能のようなものを実装したい場合、SVG画像をスタンプに使用すると拡大してもぼやけません。
下記画像は、Twitterのスタンプ画面のキャプチャです(後ろの画像は先日私が静岡旅行に行ったときに撮ったものです)。

なおTwitterのスタンプ機能のスタンプ自体は、非常に高解像度の画像が使われているようです。

画像の一部の要素を操作する必要がある場合

先述の画像のようにマウスホバーやクリック等のイベントを実装したい場合は、SVGを使用すると楽に実装できます。
また画像中の要素の色を変更したい場合などもSVGをよく使用します。
例えばレインボーカラーに光らせたい場合とかでしょうか。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

SVGの便利な使い方

ではそんな便利なSVGを便利に使う方法を、一挙にご紹介します!

クリッカブルマップを実装する(レスポンシブ対応)

クリッカブルマップとは、画像上の任意の場所をクリックすることができるようにする、
20世紀から存在する歴史ある機能。

非常に便利なこの機能ですが、

  • そもそも範囲を指定するのが大変
  • 画像サイズが変わるとクリッカブル範囲がずれるため、レスポンシブ対応が困難

という難点があります。

こちら、ジェネレーターやJavaScriptプラグインを使用すると解消することはできますが、

SVGを使用すると、もっと手軽にクリッカブルマップを実装することができるのです。

画像がSVGの場合

ベースとなる画像がSVGの場合は、比較的容易に実装することができます。

下記は、日本地図のSVGをクリッカブルマップとする例です。

See the Pen SVGによるクリッカブルマップ by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

なんとリンクさせたい要素を<a xlink:href="リンク先URL"></a>で囲むだけ!簡単!!

しかも画像にSVGを使用しているのでホバー時にCSSで色を変えることも可能です!便利!

このように、画像中の要素をあたかもHTML要素であるかのように扱えるのも、SVGの大きな魅力です。

また、きちんとレスポンシブ対応にも対応しています。上記CodePenを別タブで開き、ブラウザ幅を変更してみてください。

画像がSVGでない場合

ベースとなる画像がSVGでない場合も、少し手間はかかりますが同様の発想で実装することができます。

下記は、私が適当に作った元画像(弊社マスコットキャラクターのロージーとカール)です。これをクリッカブルマップにしてみます。

 

①まず元画像をSVG編集ソフトで開きます。今回はAdobe Illustratorを使用します。

 

②新しいレイヤーを開き、クリッカブルにしたい範囲をパスツールで設定します。
(下記画像は説明のために大雑把に設定しています。正確に範囲を設定したい場合は、パスツールで正確に囲んでください)

 

③元画像のレイヤーを削除します。
クリッカブルマップに必要なのはこの範囲のみです。

ロージーのほう、なんかお化けみたいでかわいいですね( ^ω^)

 

④パスの枠および塗りつぶしをなしにします。

 

⑤SVG形式で保存しテキストエディタで開いてコピー&ペーストし、元画像のDOMの上に重ねます。
このとき、下記の点に注意します。

  • 常に元画像とSVGのサイズが同じになるようにする(様々なブラウザ幅でテストしましょう)
  • SVGのfilltransparentに設定する

(リンク先は適当な過去記事に設定してあります)

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

この方法ですとホバー効果を実装することは出来ませんが、横幅に応じて正しくクリッカブル範囲が設定されています。

PNG画像を拡大する

前述のとおり、SVGは「拡大してもぼやけない」という性質があります。

つまりPNG画像をSVG画像に変換することができれば、画像を無限に拡大できるということ。

PNGはドットの集合体であるため、通常はこの変換は出来ません。

しかし令和の世の中、便利なツールがあるものです。

Vectorizer.AIというウェブアプリを使用すると、なんとAIによりPNG画像をSVG画像に変換することができます。

いや~すごい時代になりましたねぇ

(Vectorizer.AIはAIを使用してSVG化するため、必ずしも望み通りにSVG化されるとは限りません)

まず、弊社ロジカルスタジオのマスコットキャラクターのカール。

こちら、PNG画像なので、拡大するとやはりぼやけてしまいます。

では、先程のVectorizer.AIを使用して、SVG化してみましょう。

きれいに変換されてますね!

そして、ダウンロードしたものが下記となります。

ブラウザで拡大してみてください。どれだけ拡大してもぼやけないのが確認できるかと思います。

あとはSVGをIllustrator等で読み込み、拡大してpngで書き出せば画像拡大完了です!

余談・応用

このようにPNGをSVGに変換すると、SVGの特性を享受することができます。

ということは、SVG化を挟むとこんなこともできるということ。

T.Ktsucchi_blue

作ってもらったときに黒髪だった私の似顔絵(PNG画像)を、現在に合わせて青髪にしてみました!

この方法ですと、ビットマップ画像を塗りつぶしたとき特有のジャギー問題も解消できます。

コーディングのみならず、普段の創作作業でも工夫とアイデア次第で活かせそうですね( ^ω^)

手書き風アニメーション

SVGを使用すると、下記のようなアニメーションを実装することもできます(vivus.jsというライブラリを使用しています)。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

こちらは、SVGのstroke-dashoffset(破線の開始位置を設定する)というプロパティを利用したもの。

この値を徐々に上げていくことで、このようなアニメーションを実現しています。

モーフィング

SVGのアニメーション機能を使用すると、下記のようなパスのモーフィングも可能です!

※モーフィング・・・ある画像から別の画像へ、2次元的な動きを伴って徐々に自然に変化するアニメーションのこと

See the Pen SVGモーフィング成功例 by IchidaTatsuhiro (@ichidatatsuhiro) on CodePen.

これすごいですよね

複雑なパスでモーフィングすると、劇的な視覚的効果を与えられそうです。

具体的な実装方法は弊社ブログの過去記事をご覧ください。弊社エンジニアいっちーがわかりやすく説明してくれてます

SVGモーフィングでぬるっと変形するアニメーションを実装しよう!

派手なグラフィックを実装する

ブラウザ上で派手なグラフィックを実装する場合は主にcanvasを使用しますが、

SVGを使用してもある程度派手なグラフィックを実装することができます。

PC環境の方は下記をクリックしてください。ダイナミックに動きます!

SVGなので、自動的にレスポンシブ対応も出来ていますね。

DOMを画像化

SVGには<foreignObject>という、DOMをSVG中で描画できる機能があります。

また、SVGは画像として保存することができます。

これが何を意味するかというと、

DOMを画像化することができる

ということ!

DOMを画像化できるライブラリ「dom-to-image」は、SVGのこの機能を使用したものです。

現状JavaScriptには現状DOMを画像化するAPIは用意されていないため、そのような処理を行いたい場合はこの機能を利用します。

See the Pen dom-to-image by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

終わりに

以上、SVGの特徴や使い方を紹介してきました。

SVGには他にも様々な機能があります。詳しくは公式リファレンスをご覧ください。

SVG 要素リファレンス – SVG: スケーラブルベクターグラフィック | MDN

SVGの仕様や特徴を知ると、他にも様々な便利な使い方が思いつきそうです。

皆様もぜひいろいろ調べて、コーディングを良いものにしていってください

余談

私がコーディングを開始した2005年頃は、コーディングの参考サイトには記載されていなかったように記憶しています。

入社時「こんな便利なもんあるんや!」とびっくりした記憶があります。

本記事を執筆するにあたり、SVGの歴史を調べていたところ、2008年の記事に行き当たりました。

当該記事によると、2008年当時にはあまりSVGは使われていないようでした。

あれから16年が経過しモダンブラウザがSVGに対応した今、SVGは非常に広く使われています。

SVGの便利さを享受している私としては、非常に嬉しい限りです

(自分で書いといてなんやけど、2008年って16年前か・・・・)

ところで

弊社ロジカルスタジオでは、フロントエンドエンジニアを募集しております。

好奇心と技術力にあふれるあなた!下記リンクからお待ちしているしゅこよ