HTML/CSS

SVG ファイルを外部読み込みして CSS で色を変更する方法

何かとよく使う SVG ファイル

こんにちは!

12月となり今年もあとわずかという事実に驚愕しております。ブルブル

充電中のMacに手を当てて暖を取る今日この頃。。(bodyが結構熱くなるので、夏は嫌なんだけど冬は重宝するんですよね)

そんな師走第一回目のブログは、何かと使用頻度が高い SVG ファイルに関して。

最近マウスオーバー( hover )した際に色が変わる SVG のアイコンを実装する機会があり、その際にいろいろと詰まったことがあったので今回は、

svg ファイルを外部読み込みして CSS で色を変更する方法

と題して具体的なHTML, CSSの書き方についてまとめてみようと思います。

前回ブログはこちらから↓

そもそも svg とは

「 Scalable Vector Graphics 」の略で、画像フォーマットのの一種。大まかに下記の特徴があります。

1.画像をベクトルなどの数値データを元に画像を表現する画像フォーマットの一種

2.画像を拡大・縮小しても荒れることがない

3.CSS, JavaScript を使って色変更・アニメーションが可能

SVG 形式のデータをエディタで開いてみるとよく分かるのですが、数字の羅列で成り立っているのですよね。JPEG や PNG とは全く異なるモンなんだなー。

想定ケース

マウスオーバー( hover )するとハンバーガーの SVG 画像の色、及び「マウスオーバーで色が変わるよ」のテキストの文字色が背景色と反転する、という最近割とよく見かけるデザインを想定します。

通常時↓

マウスオーバー時↓

SVG 画像は、下記サイトからダウンロードしました。画像の種類やサイズ、色まで指定できて結構便利なサイトです。商用利用OKと記載されています。

imgタグで普通に読み込むだけだと色は変更できない

色変更とか特にしなくてよくて、単に SVG 画像を読み込みたいというときは 下記のように img タグにファイル名を記載するだけでよいのですが…

<div class="hamburgerbox">
   <h3 class="title">マウスオーバーで色が変わるよ</h3>
   <img src="./img/hamburger.svg" alt="ハンバーガー">
</div>

上記のように読み込んだ場合は SVG 画像の色を変更することはできません。

こういうふうになっちゃう( SVG のデフォルトの色が表示されるだけ)↓

ではどうすれば……??

方法① インライン SVG で表示する

HTML 内に に SVG タグを使って直接記述します。

  .hamburgerbox {
        width: 300px;
        background-color: #ffbc0d;
        border: 2px solid #ffbc0d;
        border-radius: 4px;
        color: #fff;
        transition: .3s;
        text-align: center;
        cursor: pointer;
  }
  .hamburgerbox:hover {
        color: #ffbc0d;
        background-color: #fff;
  }
  svg {
        width: 40%;
        fill: currentColor;
  }

</style>
     
  <div class="hamburgerbox">
    <h3 class="title">マウスオーバーで色が変わるよ</h3>
    <svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 128px; height: 128px; opacity: 1;" xml:space="preserve">
      <g>
        <path class="st0" d="M495.957,390.227H16.044C7.185,390.227,0,397.401,0,406.249v26.685c0,54.749,114.619,47.804,256,47.804
        s256-2.185,256-47.804v-26.685C512,397.401,504.815,390.227,495.957,390.227z"></path>
        <path class="st0" d="M42.934,353.858h426.13c15.913,0,28.794-12.891,28.794-28.794v-25.272c0-15.891-12.881-28.771-28.794-28.771
        H430.37l-61.163,61.152c-15.652,15.662-41.033,15.662-56.696,0l-61.152-61.152H42.934c-15.913,0-28.793,12.88-28.793,28.771v25.272
        C14.141,340.967,27.022,353.858,42.934,353.858z"></path>
        <path class="st0" d="M256,30.977c-141.38,0-256,74.13-256,172.554v20.739c0,8.848,7.185,16.032,16.044,16.032h479.913
        c8.858,0,16.043-7.185,16.043-16.032v-20.739C512,105.107,397.38,30.977,256,30.977z M128.706,144.118
        c-9.38,0-16.967-7.586-16.967-16.967c0-9.37,7.587-16.978,16.967-16.978c9.37,0,16.978,7.609,16.978,16.978
        C145.684,136.532,138.076,144.118,128.706,144.118z M205.076,93.205c-9.37,0-16.967-7.598-16.967-16.967
        c0-9.381,7.598-16.967,16.967-16.967c9.38,0,16.978,7.586,16.978,16.967C222.054,85.608,214.456,93.205,205.076,93.205z
          M256,161.097c-9.37,0-16.978-7.609-16.978-16.978c0-9.37,7.609-16.967,16.978-16.967c9.37,0,16.978,7.598,16.978,16.967
        C272.978,153.488,265.369,161.097,256,161.097z M306.924,93.205c-9.38,0-16.978-7.598-16.978-16.967
        c0-9.381,7.598-16.967,16.978-16.967c9.37,0,16.967,7.586,16.967,16.967C323.891,85.608,316.293,93.205,306.924,93.205z
          M383.293,144.118c-9.37,0-16.978-7.586-16.978-16.967c0-9.37,7.609-16.978,16.978-16.978c9.381,0,16.967,7.609,16.967,16.978
        C400.26,136.532,392.674,144.118,383.293,144.118z"></path>
      </g>
      </svg>
  </div>

ポイント1: SVG に fill: currentColor; を指定する

CSS で SVG に下記のスタイルを指定します。

svg {
  fill: currentColor;
}

上記を指定することによって親要素に指定されている color プロパティの値を継承することができます。

ポイント2: SVG で指定されている fill プロパティを削除する

SVG にデフォルトで指定されている fill プロパティを全て削除します。

iconmono の SVG 画像はダウンロードしてきたままの状態だと、ダウンロード時に指定した色が style タグや path タグ内に

style=”fill: rgb(75, 75, 75);”

といった具合に入っているので、それを全て削除します。

これで無事に想定の挙動(マウスオーバー時にテキストとアイコンが黄色くなる)が実現できました!

ただ、インラインで読み込んだので、ソースがめっちゃ長くなるし、アイコン一個ならいいけどこれが複数になった場合ソースはめっちゃ見にくい…

もっといい方法ないの〜〜??ということでいろいろ試した結果…

方法② use タグを使って SVG ファイルを外部読み込みする

use タグを使って SVG ファイルを外部読み込みします。

<div class="hamburgerbox">
  <h3 class="title">マウスオーバーで色が変わるよ</h3>
  <svg>
    <use xlink:href="./img/hamburger.svg#hamburger"></use>
  </svg>
</div>   

ポイント1: SVG のファイルパスを指定する

use xlink:href=”” として、SVGファイルが保存されているパスを指定します。

ポイント2: SVG ファイルの id を指定する

SVG ファイルの SVG タグ内で id を指定する箇所があるので、そこを変更します。今回は「id=”hamburger”」としました。

<svg version="1.1" id="hamburger" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="width: 128px; height: 128px; opacity: 1;" xml:space="preserve">
<!-- 以下略 -->
</svg>

上記で指定した id を use タグの一番後ろにハッシュ( # )をつけて指定します。

<svg>
  <use xlink:href="./img/hamburger.svg#hamburger"></use>
</svg>

これで外部に置いた svg ファイルを読み込むことができました!

動くサンプルはコチラ

インラインで読み込むより、こっちの方法で書いた方がコード量が断然短いし、何のファイルを読み込んでいるのかというのも分かりやすくなったと思います。

余談:use タグで SVG を読み込むとクロスドメイン制約に引っかかる?

ローカルで use タグを使って SVG ファイルを読み込んだ HTML ファイルをブラウザで閲覧しようとすると、クロスドメイン制約に引っかかるようで、表示できませんでした。

Mac のローカルサーバーを起動して閲覧してみたら、ちゃんと表示できた。

う〜ん。。ここら辺なぜだかちょっとよく分からないんですが、Mac のローカルサーバーを起動する方法は下記記事ご参考まで。

ちなみに Docker 環境ではこのようなことは起こりませんでした。やっぱり Docker さんは便利なんだな〜〜。。

まとめ

今回は SVG ファイルを外部読み込みして CSS で色を変更する方法についてまとめてみました。

上述の方法を知るまでは JavaScript で動的に色を変更するしかないのかな?とか pollyfill を導入してなんとかしようとしたりして結構時間溶かしてしまったんですが。。。

CSS の currentColor で親要素の色を継承することができるし、外部読み込みでシンプルなコードで読み込むことができるし、結構簡単だったんだなぁ…と。

知ってるのと知らないのとでは実装スピードに何倍もの差が出てしまうのが、この世界のキビシイところですね。

ここまでお読みいただき、ありがとうございました!