svgアイコンをsymbolで定義してuseで効率的に使う
この記事は最終更新日から1年以上が経過しています。
芽萌丸プログラミング部@programming
投稿日 2020/7/8
更新日 2023/7/6 ✏

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のライブラリをロードするというのは非常に非効率ですし^^;)


芽萌丸プログラミング部
芽萌丸プログラミング部@programming
プログラミング関連アカウント。Web標準技術を中心に書いていきます。フロントエンドからサーバサイドまで JavaScript だけで済ませたい人たちの集いです。記事は主に @TanakaSoftwareLab が担当。