【SVG】IcoMoonでグラデーションが抜けてしまう原因とその対処法

IcoMoonは任意のSVGファイルをアップロードするだけで簡単にSVG Spriteを生成できる無料のオンラインサービスです。
既成のアイコンセットもフリーで使えるので、便利だなぁと昔からちょこちょこ利用させてもらっていました。

しかし、今回グラデーションを使ったイラストをSVGスプライト化しようとしたところ、

なぜか色が全て真っ黒!

という事象が発生しました。

今回はその原因と対処法をまとめています。どなたかの参考になれば幸いです。

IcoMoonにアップロードした時点でグラデーションが抜けてしまう

私はSVGスプライト化したファイルを使った時にようやくグラデ抜けに気がついたんですが、どうやらアップロード時点ですでに抜けていたようです。

以下のグラデアイコン素材をお借りしてテストしてみました。


icons8

IcoMoonのアップロードページに行き、アップロードボタンからこれらのファイルを選択すると、、

黒くなった!
*ちょっとわかりづらいですが本来カラーのものはそのまま表示されます

調べてみると、IcoMoonのGoogleグループ(公式かは不明)にこんな情報がありました。

(質問)
Illustratorであらかじめ決められたグラデーションが適用されたアイコンがあります。 SVGを保存してからIcomoonセットにアップロードすると、グラデーションが黒に変換されます。 これは起こるはずですか? これはエラーですか? Icomoonアップロードのグラデーションのルールは何ですか?

(回答)
グラデーションはめったに使用されないため、IcoMoonは現在それらをサポートしていません。 将来、グラデーションのサポートを追加する可能性があります。

* 原文英語/Google翻訳
Gradient upload issues

IcoMoonではグラデーションのサポートをそもそもしていないとのこと。
2017/03/10時点では「I am in the process of rewriting the IcoMoon app. It’s going to take a while.」とあり、グラデーション対応へ動いていそうな情報がありました。(4年前ですが、、

次に、具体的になぜグラデーションが抜けてるかを確認してみます。
アップロード前とスプライト後のSVGファイルのコードがこちら。

icons8delete.svgの場合
<アップロード前>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64px" height="64px">
	<linearGradient id="fbsFAcPTNuInJg1GESjdha" x1="32" x2="32" y1="7.001" y2="56.998" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
		<stop offset="0" stop-color="#1a6dff" />
		<stop offset="1" stop-color="#c822ff" />
	</linearGradient>
	<path fill="url(#fbsFAcPTNuInJg1GESjdha)" d="M49.757,56.999c-0.768,0-1.536-0.292-2.121-0.877L32,40.485L16.364,56.121 c-1.17,1.169-3.073,1.169-4.243,0l-4.243-4.243c-1.17-1.17-1.17-3.073,0-4.243L23.515,32L7.879,16.364 c-1.17-1.17-1.17-3.073,0-4.243l4.243-4.243c1.169-1.17,3.072-1.171,4.243,0L32,23.515L47.636,7.879c1.17-1.171,3.073-1.17,4.243,0 l4.243,4.243c1.17,1.17,1.17,3.073,0,4.243L40.485,32l15.636,15.636c1.17,1.17,1.17,3.073,0,4.243l-4.243,4.243 C51.293,56.706,50.525,56.999,49.757,56.999z M32,37.657l17.05,17.05c0.39,0.39,1.025,0.389,1.415,0l4.243-4.243 c0.39-0.39,0.39-1.024,0-1.415L37.657,32l17.05-17.05c0.39-0.39,0.39-1.024,0-1.415l-4.243-4.243c-0.39-0.39-1.025-0.391-1.415,0 L32,26.343L14.95,9.293c-0.39-0.39-1.025-0.389-1.415,0l-4.243,4.243c-0.39,0.39-0.39,1.024,0,1.415L26.343,32L9.293,49.05 c-0.39,0.39-0.39,1.024,0,1.415l4.243,4.243c0.389,0.389,1.024,0.39,1.415,0L32,37.657z" />
	<linearGradient id="fbsFAcPTNuInJg1GESjdhb" x1="32" x2="32" y1="11.94" y2="52.06" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
		<stop offset="0" stop-color="#6dc7ff" />
		<stop offset="1" stop-color="#e6abff" />
	</linearGradient>
	<path fill="url(#fbsFAcPTNuInJg1GESjdhb)" d="M52.061 14.061L49.939 11.939 32 29.879 14.061 11.939 11.939 14.061 29.879 32 11.939 49.939 14.061 52.061 32 34.121 49.939 52.061 52.061 49.939 34.121 32z" />
</svg>

<アップロード後>

<symbol id="icons8delete" viewBox="0 0 32 32">
	<path d="M24.878 28.5c-0.384 0-0.768-0.146-1.061-0.439l-7.818-7.819-7.818 7.818c-0.585 0.584-1.537 0.584-2.122 0l-2.122-2.122c-0.585-0.585-0.585-1.537 0-2.122l7.819-7.817-7.818-7.818c-0.585-0.585-0.585-1.537 0-2.122l2.122-2.122c0.585-0.585 1.536-0.586 2.122 0l7.818 7.819 7.818-7.818c0.585-0.586 1.537-0.585 2.122 0l2.122 2.122c0.585 0.585 0.585 1.537 0 2.122l-7.819 7.817 7.818 7.818c0.585 0.585 0.585 1.537 0 2.122l-2.122 2.122c-0.293 0.292-0.677 0.439-1.061 0.439zM16 18.828l8.525 8.525c0.195 0.195 0.512 0.195 0.707 0l2.122-2.122c0.195-0.195 0.195-0.512 0-0.707l-8.526-8.524 8.525-8.525c0.195-0.195 0.195-0.512 0-0.707l-2.122-2.122c-0.195-0.195-0.512-0.196-0.707 0l-8.524 8.525-8.525-8.525c-0.195-0.195-0.513-0.194-0.707 0l-2.122 2.122c-0.195 0.195-0.195 0.512 0 0.708l8.525 8.524-8.525 8.525c-0.195 0.195-0.195 0.512 0 0.707l2.122 2.122c0.194 0.195 0.512 0.195 0.708 0l8.524-8.525z"></path>
	<path d="M26.030 7.030l-1.061-1.061-8.97 8.97-8.97-8.97-1.061 1.061 8.97 8.97-8.97 8.97 1.061 1.061 8.97-8.97 8.97 8.97 1.061-1.061-8.97-8.97z"></path>
</symbol>

記述形式やサイズが変わってますが、グラデーションを表現するためのlinearGradientタグが削除されてしまっていることがわかります。

それならば、SVGスプライトファイルの構造にグラデーションが残っているコードを置き換えたらどうだろうと思い立って検証。
次の方法でグラデを復元できることを確認しました。

SVGスプライトファイルのsymbol内のコードを書き換える

最初にIcoMoonで色抜けた状態のSVGスプライトファイルを用意したら、やることは3つです。

該当symbolタグ内のコードを元のSVGファイルのsvgタグ内コードに書き換える

何十ものSVGファイルをスプライト化することもあるかと思いますが、1つのSVG画像につき1つのsymbol要素で記述される形で構成されます。

まずSVGスプライトからグラデーションが抜けてしまったSVGのsymbolタグを確認し、その内側のコードをIcoMoonアップロード前のSVGファイルのコード(SVGタグ内)に置き換えてあげましょう。

さきほど書いた<アップロード後>のコードを上の通り修正したものがこちら。

<SVGスプライトファイルの修正版>

<symbol id="icons8delete" viewBox="0 0 32 32">
	<linearGradient id="fbsFAcPTNuInJg1GESjdha" x1="32" x2="32" y1="7.001" y2="56.998" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
		<stop offset="0" stop-color="#1a6dff" />
		<stop offset="1" stop-color="#c822ff" />
	</linearGradient>
	<path fill="url(#fbsFAcPTNuInJg1GESjdha)" d="M49.757,56.999c-0.768,0-1.536-0.292-2.121-0.877L32,40.485L16.364,56.121 c-1.17,1.169-3.073,1.169-4.243,0l-4.243-4.243c-1.17-1.17-1.17-3.073,0-4.243L23.515,32L7.879,16.364 c-1.17-1.17-1.17-3.073,0-4.243l4.243-4.243c1.169-1.17,3.072-1.171,4.243,0L32,23.515L47.636,7.879c1.17-1.171,3.073-1.17,4.243,0 l4.243,4.243c1.17,1.17,1.17,3.073,0,4.243L40.485,32l15.636,15.636c1.17,1.17,1.17,3.073,0,4.243l-4.243,4.243 C51.293,56.706,50.525,56.999,49.757,56.999z M32,37.657l17.05,17.05c0.39,0.39,1.025,0.389,1.415,0l4.243-4.243 c0.39-0.39,0.39-1.024,0-1.415L37.657,32l17.05-17.05c0.39-0.39,0.39-1.024,0-1.415l-4.243-4.243c-0.39-0.39-1.025-0.391-1.415,0 L32,26.343L14.95,9.293c-0.39-0.39-1.025-0.389-1.415,0l-4.243,4.243c-0.39,0.39-0.39,1.024,0,1.415L26.343,32L9.293,49.05 c-0.39,0.39-0.39,1.024,0,1.415l4.243,4.243c0.389,0.389,1.024,0.39,1.415,0L32,37.657z" />
	<linearGradient id="fbsFAcPTNuInJg1GESjdhb" x1="32" x2="32" y1="11.94" y2="52.06" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
		<stop offset="0" stop-color="#6dc7ff" />
		<stop offset="1" stop-color="#e6abff" />
	</linearGradient>
	<path fill="url(#fbsFAcPTNuInJg1GESjdhb)" d="M52.061 14.061L49.939 11.939 32 29.879 14.061 11.939 11.939 14.061 29.879 32 11.939 49.939 14.061 52.061 32 34.121 49.939 52.061 52.061 49.939 34.121 32z" />
</symbol>

該当symbolタグviewBox属性を元のSVGファイルのsvgタグviewBox属性の値に書き換える

次に、SVGファイルのviewBox属性をスプライトファイルのsymbolタグに反映します。
*サイズは元SVGファイルのものになります

<SVGスプライトファイルの修正版2>

<symbol id="icons8delete" viewBox="0 0 64 64">
	<linearGradient id="fbsFAcPTNuInJg1GESjdha" x1="32" x2="32" y1="7.001" y2="56.998" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
		<stop offset="0" stop-color="#1a6dff" />
		<stop offset="1" stop-color="#c822ff" />
	</linearGradient>
	<path fill="url(#fbsFAcPTNuInJg1GESjdha)" d="M49.757,56.999c-0.768,0-1.536-0.292-2.121-0.877L32,40.485L16.364,56.121 c-1.17,1.169-3.073,1.169-4.243,0l-4.243-4.243c-1.17-1.17-1.17-3.073,0-4.243L23.515,32L7.879,16.364 c-1.17-1.17-1.17-3.073,0-4.243l4.243-4.243c1.169-1.17,3.072-1.171,4.243,0L32,23.515L47.636,7.879c1.17-1.171,3.073-1.17,4.243,0 l4.243,4.243c1.17,1.17,1.17,3.073,0,4.243L40.485,32l15.636,15.636c1.17,1.17,1.17,3.073,0,4.243l-4.243,4.243 C51.293,56.706,50.525,56.999,49.757,56.999z M32,37.657l17.05,17.05c0.39,0.39,1.025,0.389,1.415,0l4.243-4.243 c0.39-0.39,0.39-1.024,0-1.415L37.657,32l17.05-17.05c0.39-0.39,0.39-1.024,0-1.415l-4.243-4.243c-0.39-0.39-1.025-0.391-1.415,0 L32,26.343L14.95,9.293c-0.39-0.39-1.025-0.389-1.415,0l-4.243,4.243c-0.39,0.39-0.39,1.024,0,1.415L26.343,32L9.293,49.05 c-0.39,0.39-0.39,1.024,0,1.415l4.243,4.243c0.389,0.389,1.024,0.39,1.415,0L32,37.657z" />
	<linearGradient id="fbsFAcPTNuInJg1GESjdhb" x1="32" x2="32" y1="11.94" y2="52.06" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
		<stop offset="0" stop-color="#6dc7ff" />
		<stop offset="1" stop-color="#e6abff" />
	</linearGradient>
	<path fill="url(#fbsFAcPTNuInJg1GESjdhb)" d="M52.061 14.061L49.939 11.939 32 29.879 14.061 11.939 11.939 14.061 29.879 32 11.939 49.939 14.061 52.061 32 34.121 49.939 52.061 52.061 49.939 34.121 32z" />
</symbol>

他のsymbolのlinearGradientタグとIDが重複しないよう付与する

最後に、linearGradientタグのIDが他のsymbolタグと重複していないことを確認します。
(重複すると、最初にでてくるIDのみグラデが有効になり、それ以降のグラデーションが抜けてしまうため)

上の場合、2行目「fbsFAcPTNuInJg1GESjdha」、7行目「fbsFAcPTNuInJg1GESjdhb」のIDが他のsymbolで使われていなければOK。

完成

こんな感じでSVGスプライトファイルのコードを全て修正すると、下記のイメージのようになります。
実際に適用しているサンプルファイルも作ったので合わせてご覧ください。

Sample

まとめ

今回グラデーション付きSVGイラストを1ページに大量に表示させる必要があったことで気づいたんですが、これまで使っていて全く気づきませんでした。
類似事例の報告もなかなか見つからなかったので、グラデSVG自体あまり使われないのか、SVGスプライトがあんまり使われていないのか、IcoMoon以外のツールでスプライト化を行なっている人が多いのか、どうなんでしょうか( ´Д`)

今回は一部だけグラデがかかっているアイコン・イラストをスプライト化する際のことだったので、危なくグラデ抜けに気づかずスルーしてしまうところでした。
IcoMoonを使う時に少しだけ留意しておくといいかもしれません。

IcoMoonやSVGに関する記事は他にもあるのでよければご覧ください!