SVGがIEのみ黒くなってしまう場合の対処法

この記事は最終更新から4年以上が経過しています。情報が古くなっている可能性があります。

こんにちは、しばです。
先日、色付きのsvgがIE11でだけ黒一色になってしまう事象に遭遇しました。
日本語・英語共に全く事例を見かけなかったので、諸々しらべて自分なりに結論をまとめました!

原因はあんまりこういう使い方する人いないのかもなーというものでしたが、同事象に遭遇の方は参考にどうぞ。

発生した事象と経緯について

本来はカラーのこちらの画像。
モデルは毎度おなじみのポストくんです(アプリ参照)。

これが、IE11だけこういう風に黒くなってしまう。

ブラック!!

IE11のほか、Edge、FireFox、Chrome(Win/Mac)、safari(Mac)で確認しましたが、IE11以外はカラーで表示されました。

このSVGは、useタグのxlink属性で外部のSVGスプライトを参照して使用していました。
本来、useタグを使用した外部SVGファイルの参照はIE11では出来ないんですが、IcoMoonで生成したSVGスプライトファイルはsvgxuse.jsというファイルを読み込むことで対応させているようです。これに関してはこちらの記事がわかりやすかったです。

そういう使い方だったのでまず疑ったのは、svgxuse.jsでは対応しきれず情報の欠損か何かが起きた?ということ。

それでいくつかテスト用にSVGスプライトファイルを生成しましたが、IE11でもカラーでの表示を確認。
念のためスプライト前の単体画像の表示も確認しましたが同様にカラーでした。

この段階で、

  1. スプライトさせるSVG画像によって、svgxuse.jsの挙動が異なり情報の欠損が発生した
  2. svgxuse.jsのせいじゃなく、他に原因がある

この2パターンのどちらかかな?と考えました。

原因

svgxuse.jsがIE11に何をしてるのかってことを調べるより、まず他を潰した方が早いと思ったので、他の原因を先に考えてみました。

スプライト以外に何かSVG画像にやっただろうか?

圧縮だ(゜∀゜)!

この事象に遭遇したときGulpを使っており、他の画像ファイルと一緒に「gulp-imagemin」 という画像圧縮プラグインを使って処理をかけていました。

となると、圧縮によってコードの一部が(特に色に関する記述が)IE11では評価できない書き方になってしまった可能性が高い。
圧縮前と圧縮後のファイルの中身を比較しました。

<!-- 圧縮前 -->
<path fill="#18696e" style="fill: var(--color2, #18696e)" d="(省略)">

<!-- 圧縮後 -->
<path fill="var(--color2, #18696e)" d="(省略)">

*色に関する記述のみ抜粋
*どちらもstyle要素(<style>〜</style>)の記述なし

圧縮前はfill属性とstyle属性でそれぞれカラーコードが異なる書き方で指定されていますが、圧縮後はfill属性にvar() 関数の指定だけになっています。
このvar() 関数は変数を呼び出すために使われるもので、その変数はCSS変数だったりCSSカスタムプロパティと呼ばれます。

で、このCSS変数(及びvar() 関数)はIE11は未対応です。(Can I Use調べ)

原因判明。

つまり、

  • 圧縮前は「fill属性のカラーコード」と「style属性のfillプロパティのvar() 関数」を併用して書かれてあったのでどちらかで色を評価していた
  • 圧縮したことでvar() 関数のみの記述になった。
  • IE11はCSS変数(var() 関数)未対応なので、fill属性のコード自体を評価できず、fill属性の初期値(黒色)に。

ということでした。

※2019/4/23追記)
情報提供いただきました!
上記に加えて、透過度を含めた8桁のカラーコードを使っている場合もIE11非対応のため評価できず、黒くなるようです。(確認内容は後述

確認してみる

間違いないか、SVGの色指定をいじって確認してみました。

まず豚のSVG画像を4枚用意。(notスプライト)
1番目の画像からそれぞれ以下のような色指定に修正します。

  1. <path fill=”色指定” d=”(省略)” >
  2. <path style=”fill: 色指定” d=”(省略)” >
  3. <path fill=”var(変数, 色指定)” d=”(省略)” >
  4. <path style=”fill: var(変数,色指定)” d=”(省略)” >

*いずれもstyle要素(<style>〜</style>)の記述なし

次にHTMLでこれらの画像を並べて表示させます。

<div class="testBox">
	<p><img src="test01.svg"><br>fill="#色"</p>
	<p><img src="test02.svg"><br>style="fill: #色" </p>
	<p><img src="test03.svg"><br>fill="var(--color2, #色)"</p>
	<p><img src="test04.svg"><br>style="fill: var(--color2, #色)"</p>
</div>
<style>
	.testBox { display: flex; width: 1000px; }
	p {	width: 25%;	}
	img {	width: 80%; height: auto;	}
</style>

これで3番目と4番目の豚がIE11で黒で表示されたら原因確定。

これを各ブラウザの表示を確認した結果、こうなりました。

Mac/Chrome 全て色付き
Mac/safari 全て色付き
win10 Edge 全て色付き
win10 chrome 全て色付き
win7 IE11 左2つは色付き、右2つは黒
win7 chrome 全て色付き
win7 firefox 全て色付き


Chromeその他ブラウザの場合


IE11の場合

色をvar()関数の指定だけにした右2つの画像だけ、IE11で黒くなったことがわかります。

どういう時に色指定がvar()関数だけになるのか?

結局var()関数だけになる時ってどういうとき?何に注意すればいいの?
と思ったので、黒くなったSVG画像の編集段階+αを追って調べて見ました。

(1) Illustratorから切り出したSVG

<svg xmlns="http://www.w3.org/2000/svg" width="327.98" height="257" viewBox="0 0 327.98 257">
<defs><style>
.cls-1{fill:#fedc78;}
</style></defs>
<title>タイトル</title>
<g id="レイヤー_2" data-name="レイヤー 2"><path class="cls-1" d="(以下省略)"></g></svg>

→ 問題なし。色に関してはstyle要素にまとめられていますが、「fill: 色指定」で書かれているので問題ありませんでした。

(2) (1)の画像を圧縮(gulp-imagemin)

<svg xmlns="http://www.w3.org/2000/svg" width="327.98" height="257"><g data-name="レイヤー 2">
<path fill="#fedc78" d="(省略)">
</g></svg>

→問題なし。style要素が各パスのfill属性に移動しただけで、「fill: 色指定」のままでした。

(3) (1)の画像をIcoMoonでスプライト

<svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="icon-pig01_ordinal" viewBox="0 0 41 32">
<title>タイトル</title>
<path fill="#fedc78" style="fill: var(--color1, #fedc78)" d="(省略)">
</symbol>
</defs>
</svg>

→ こちらは圧縮せずスプライトしたパターン。こちらも問題なし。ただこの段階で、「fill属性のカラーコード」と「style属性のfillプロパティのvar()関数」が併用されて書かれるようになります。

(4) (3)の画像を圧縮(gulp-imagemin)

<svg aria-hidden="true" style="position:absolute;width:0;height:0" xmlns="http://www.w3.org/2000/svg" overflow="hidden">
<defs><symbol id="icon-pig01_ordinal" viewBox="0 0 41 32">
<path fill="var(--color1, #fedc78)" d="(省略)">
</symbol></defs></svg>

ここで色指定がvar()関数だけに!
gulp-imageminの代わりに、SVGの圧縮画像で有名なSVGOMGで処理しても同じ書き方になりました。

圧縮前のSVGに「fill属性のカラーコード」と「style属性のfillプロパティのvar()関数」の両方が書かれている場合、どの圧縮処理でもこうなってしまうのかも知れませんね。

※追記)カラーコード8桁の場合の比較

透過度も含めて表す8桁のRGBAカラーコード(#RRGGBBAA)がありますが、これをfill属性に使用する場合も黒色(初期値)になってしまいます。

教えていただいたので確認してみました。


Chromeその他ブラウザの場合


IE11、Edgeの場合

このケースではIE11だけでなくEdgeも黒色になります。
これはvar() 関数同様、IE11とEdgeがRGBAカラーコード形式に非対応であるため。svgのfill属性は初期値である黒に、backgroundに指定した方は初期値のtransparentになってしまいました。

RGBAカラーコードはほとんど使ったことがなく気づかなかったんですが、教えてくださった方によれば、inkscapeでは標準で8桁を入力できてしまうとのこと。

原因が見当たらなかったらここら辺も確認すると良さそうです!

まとめ

ということで結論です。

少なくとも、IcoMoonでSVGスプライトしたものをgulp-imageminやSVGOMGで圧縮するとIE11で黒くなる。

意図的でなくても私の場合のように、他の画像たちに紛れて圧縮してしまうかもしれません。
あるいは、「スプライト→圧縮」という処理を経てなくても生成方法や何かしらの処理によって、黒く表示されることがあるかもしれません。

コードの記述方法の問題なので、とにかく黒く表示されてしまったらSVG画像内の色の指定方法を確認しましょう!

  • fill=”var(変数, 色指定)”
  • style=”fill: var(変数, 色指定)
  • fill=”#000000FF”

このようなvar()関数や8桁カラーコードを使った記述だけだとアウトです!
その場合は、手作業でfill=”色指定” またはstyle=”fill: 色指定” に修正しましょう。

IE11サポート終了までは気が抜けませんね。
以上、こういうこともあるよ!というご紹介でした。

おまけ

今回とは原因が異なりますが、他にもIE11でSVGが黒くなってしまうという事例がありました。

こちらは「SVG内に<style>要素が含まれており、svgが動的に使用されているときにstyle要素が評価されない場合がある。パスのstyle属性にcssを移動させるべき」という不具合?のようです。
ご紹介まで。