svgアイコンをsymbolで定義してuseで効率的に使う
svgとはXMLベースの2次元ベクターイメージ用の画像形式の1つです。一般的なイメージ画像とは異なりsvgはただのテキストですので、エディタ等で扱い易く、ファイルサイズも小さくできる(場合が多い)というメリットがあります。 画像をアイコンとして使う場合は同じページに何度も貼り付けることが多いと思いますが、サイズがいくら小さいからと言っても同じsvg画像を毎回コピペで貼り付けていてはとても非効率です。
そこで今回は、svg画像をページ内で効率的に再利用する方法のご紹介です。 ページ内で一度定義したsvg画像(svgアイコン)を再利用するために<symbol>
と<use>
要素を使います。
ちなみに今回の方法は外部CSSやJSライブラリ等の読み込みは一切不要です!
目次
実装手順
1) svgアイコンのスタイル定義
<style type="text/css">
/* SVGアイコン定義コンテナクラス */
.svg-defs {
width: 0;
height: 0;
visibility: hidden;
position: fixed;
bottom: 0;
}
/* SVGアイコンクラス */
.icon {
width: 1em;
height: 1em;
fill: currentColor;
position: relative;
display: inline-block;
vertical-align: baseline;
/* baselineより垂直方向にちょっとだけ下げる */
top: 0.125em;
}
</style>
.icon
- svgアイコンに付与するスタイル
- アイコンの微妙なズレを補正
fill: currentColor
で親要素の色を引き継ぎ
.svg-defs
- この後で定義するsvgアイコン定義用コンテナのスタイル
2) svgアイコンの定義
<body>
<!-- 利用するSVGアイコンのシンボル定義用コンテナ -->
<svg class="svg-defs" xmlns="http://www.w3.org/2000/svg">
<!-- #alert シンボル -->
<symbol viewBox="0 0 16 16" id="alert">
<path fill-rule="evenodd" d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"></path>
</symbol>
<!-- #arrow-down シンボル -->
<symbol viewBox="0 0 10 16" id="arrow-down">
<path fill-rule="evenodd" d="M7 7V3H3v4H0l5 6 5-6z"></path>
</symbol>
<!-- #thumbsup シンボル -->
<symbol viewBox="0 0 16 16" id="thumbsup">
<path fill-rule="evenodd" d="M6.956 1.745C7.021.81 7.908.087 8.864.325l.261.066c.463.116.874.456 1.012.965.22.816.533 2.511.062 4.51a9.84 9.84 0 0 1 .443-.051c.713-.065 1.669-.072 2.516.21.518.173.994.681 1.2 1.273.184.532.16 1.162-.234 1.733.058.119.103.242.138.363.077.27.113.567.113.856 0 .289-.036.586-.113.856-.039.135-.09.273-.16.404.169.387.107.819-.003 1.148a3.163 3.163 0 0 1-.488.901c.054.152.076.312.076.465 0 .305-.089.625-.253.912C13.1 15.522 12.437 16 11.5 16v-1c.563 0 .901-.272 1.066-.56a.865.865 0 0 0 .121-.416c0-.12-.035-.165-.04-.17l-.354-.354.353-.354c.202-.201.407-.511.505-.804.104-.312.043-.441-.005-.488l-.353-.354.353-.354c.043-.042.105-.14.154-.315.048-.167.075-.37.075-.581 0-.211-.027-.414-.075-.581-.05-.174-.111-.273-.154-.315L12.793 9l.353-.354c.353-.352.373-.713.267-1.02-.122-.35-.396-.593-.571-.652-.653-.217-1.447-.224-2.11-.164a8.907 8.907 0 0 0-1.094.171l-.014.003-.003.001a.5.5 0 0 1-.595-.643 8.34 8.34 0 0 0 .145-4.726c-.03-.111-.128-.215-.288-.255l-.262-.065c-.306-.077-.642.156-.667.518-.075 1.082-.239 2.15-.482 2.85-.174.502-.603 1.268-1.238 1.977-.637.712-1.519 1.41-2.614 1.708-.394.108-.62.396-.62.65v4.002c0 .26.22.515.553.55 1.293.137 1.936.53 2.491.868l.04.025c.27.164.495.296.776.393.277.095.63.163 1.14.163h3.5v1H8c-.605 0-1.07-.081-1.466-.218a4.82 4.82 0 0 1-.97-.484l-.048-.03c-.504-.307-.999-.609-2.068-.722C2.682 14.464 2 13.846 2 13V9c0-.85.685-1.432 1.357-1.615.849-.232 1.574-.787 2.132-1.41.56-.627.914-1.28 1.039-1.639.199-.575.356-1.539.428-2.59z" />
</symbol>
<!-- ページで利用したいシンボルをここに追加します -->
</svg>
<body>
の直後に<svg class="svg-defs">...</svg>
を設置します。これにより、この要素内の<symbol>
で定義されたsvg画像をid指定で使いまわせるようになります。
TIP: symbol要素の作成
今回はocticonsデモやBootstrap Iconsからコピーさせていただいたsvg要素を元に加工しました。具体的には、コピーしたsvg要素からwidth属性と height属性を削除し、親要素名をsvgからsymbolに書き換え、任意のid属性を付与しました。 もちろん自作のsvg画像データも利用できます。
3) svgアイコンの利用
<!-- alertアイコン -->
<svg class="icon"><use xlink:href="#alert" /></svg>
たったこれだけでsvgアイコン定義用コンテナの<symbol id="alert">
で定義したsvgアイコンを呼び出すことができます。
サンプルコード
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<title>Hello, SVG Icons!</title>
<style type="text/css">
/* SVGアイコン定義コンテナクラス */
.svg-defs {
width: 0;
height: 0;
visibility: hidden;
}
/* SVGアイコンクラス */
.icon {
width: 1em;
height: 1em;
fill: currentColor;
position: relative;
display: inline-block;
vertical-align: baseline;
/* baselineより垂直方向にちょっとだけ下げる */
top: 0.125em;
}
</style>
</head>
<body class="container">
<!-- 利用するSVGアイコンのシンボル定義用コンテナ -->
<svg xmlns="http://www.w3.org/2000/svg" class="svg-defs">
<!-- #alert シンボル -->
<symbol viewBox="0 0 16 16" id="alert">
<path fill-rule="evenodd" d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"></path>
</symbol>
<!-- #arrow-down シンボル -->
<symbol viewBox="0 0 10 16" id="arrow-down">
<path fill-rule="evenodd" d="M7 7V3H3v4H0l5 6 5-6z"></path>
</symbol>
<!-- #thumbsup シンボル -->
<symbol viewBox="0 0 16 16" id="thumbsup">
<path fill-rule="evenodd" d="M6.956 1.745C7.021.81 7.908.087 8.864.325l.261.066c.463.116.874.456 1.012.965.22.816.533 2.511.062 4.51a9.84 9.84 0 0 1 .443-.051c.713-.065 1.669-.072 2.516.21.518.173.994.681 1.2 1.273.184.532.16 1.162-.234 1.733.058.119.103.242.138.363.077.27.113.567.113.856 0 .289-.036.586-.113.856-.039.135-.09.273-.16.404.169.387.107.819-.003 1.148a3.163 3.163 0 0 1-.488.901c.054.152.076.312.076.465 0 .305-.089.625-.253.912C13.1 15.522 12.437 16 11.5 16v-1c.563 0 .901-.272 1.066-.56a.865.865 0 0 0 .121-.416c0-.12-.035-.165-.04-.17l-.354-.354.353-.354c.202-.201.407-.511.505-.804.104-.312.043-.441-.005-.488l-.353-.354.353-.354c.043-.042.105-.14.154-.315.048-.167.075-.37.075-.581 0-.211-.027-.414-.075-.581-.05-.174-.111-.273-.154-.315L12.793 9l.353-.354c.353-.352.373-.713.267-1.02-.122-.35-.396-.593-.571-.652-.653-.217-1.447-.224-2.11-.164a8.907 8.907 0 0 0-1.094.171l-.014.003-.003.001a.5.5 0 0 1-.595-.643 8.34 8.34 0 0 0 .145-4.726c-.03-.111-.128-.215-.288-.255l-.262-.065c-.306-.077-.642.156-.667.518-.075 1.082-.239 2.15-.482 2.85-.174.502-.603 1.268-1.238 1.977-.637.712-1.519 1.41-2.614 1.708-.394.108-.62.396-.62.65v4.002c0 .26.22.515.553.55 1.293.137 1.936.53 2.491.868l.04.025c.27.164.495.296.776.393.277.095.63.163 1.14.163h3.5v1H8c-.605 0-1.07-.081-1.466-.218a4.82 4.82 0 0 1-.97-.484l-.048-.03c-.504-.307-.999-.609-2.068-.722C2.682 14.464 2 13.846 2 13V9c0-.85.685-1.432 1.357-1.615.849-.232 1.574-.787 2.132-1.41.56-.627.914-1.28 1.039-1.639.199-.575.356-1.539.428-2.59z" />
</symbol>
<!-- #alarm-fill シンボル -->
<symbol viewBox="0 0 16 16" id="alarm-fill">
<path fill-rule="evenodd" d="M5.5.5A.5.5 0 0 1 6 0h4a.5.5 0 0 1 0 1H9v1.07a7.002 7.002 0 0 1 3.537 12.26l.817.816a.5.5 0 0 1-.708.708l-.924-.925A6.967 6.967 0 0 1 8 16a6.967 6.967 0 0 1-3.722-1.07l-.924.924a.5.5 0 0 1-.708-.708l.817-.816A7.002 7.002 0 0 1 7 2.07V1H5.999a.5.5 0 0 1-.5-.5zM.86 5.387A2.5 2.5 0 1 1 4.387 1.86 8.035 8.035 0 0 0 .86 5.387zM13.5 1c-.753 0-1.429.333-1.887.86a8.035 8.035 0 0 1 3.527 3.527A2.5 2.5 0 0 0 13.5 1zm-5 4a.5.5 0 0 0-1 0v3.882l-1.447 2.894a.5.5 0 1 0 .894.448l1.5-3A.5.5 0 0 0 8.5 9V5z" />
</symbol>
</svg>
<!-- 使い方 -->
<h1>
<!-- #thumbsupアイコンを使う: -->
<svg class="icon"><use xlink:href="#thumbsup" /></svg>
symbolとuseでsvgアイコンを効率的に使う
</h1>
<h1>
<!-- #arrow-downアイコンを使う: -->
<svg class="icon"><use xlink:href="#arrow-down" /></svg>
arrow-down
<svg class="icon"><use xlink:href="#alarm-fill" /></svg>
</h1>
<h1>
<!-- #alertアイコンを使う: -->
<svg class="icon"><use xlink:href="#alert" /></svg>
alert
</h1>
<h2>
<!-- #alertアイコンを使う: -->
<svg class="icon"><use xlink:href="#alert" /></svg>
alert
</h2>
<h3>
<!-- #alertアイコンを使う: -->
<svg class="icon"><use xlink:href="#alert" /></svg>
alert
</h3>
<h4>
<!-- #alertアイコンを使う: -->
<svg class="icon"><use xlink:href="#alert" /></svg>
alert
</h4>
<h5 class="text-danger">
<!-- #alertアイコンを使う: -->
<svg class="icon"><use xlink:href="#alert" /></svg>
alert
</h5>
<h5 class="btn btn-success">
<!-- #alertアイコンを使う: -->
<svg class="icon"><use xlink:href="#alert" /></svg>
alert
</h5>
<h5 class="btn btn-outline-primary">
arrow-down
<!-- #arrow-downアイコンを使う: -->
<svg class="icon"><use xlink:href="#arrow-down" /></svg>
</h5>
<div class="alert alert-warning">
<!-- #alertアイコンを使う: -->
<svg class="icon">
<use xlink:href="#alert" /></svg>
alert
<div class="text-danger">
<!-- #alertアイコンを使う: -->
<svg class="icon">
<use xlink:href="#alert" /></svg>
text-danger
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.5.0.min.js" integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
</body>
</html>
実行例
ひとこと
今回のように外部ライブラリを一切使用せずにsvgアイコンを利用できるというのは、導入が手軽というのもありますが、それ以上にページを軽量化できるというメリットは大きいと思います。(たった数個のアイコンを使いたいがために重たいfontawesomeのライブラリをロードするというのは非常に非効率ですし^^;)