Web制作

【SVG】SVGアイコンのカラーをCSSで変更したい!

この記事の所要時間: 1448
【SVG】SVGアイコンのカラーをCSSで変更したい!

SVGを使うメリットは拡大・縮小に強く、またjpgやpngのようなラスタ画像と違いCSSによって手軽に色を変えられる柔軟性にあります。その反面いろいろな制約が多く、これまでの画像と違い扱いが難しかったりします。

CSSでサクッと色変更するにもそれなりの作法が必要で知らないと簡単にハマってしまいます。そして見事にハマったので、ここにその時の軌跡を残しておこうと思います。

この記事の目次

やりたかったこと

検索ボタン

この画像のボタンのようにグラデーションの背景にSVGアイコンを重ねてSVGアイコンの塗りを調節する。
なるほどなるほど。あれをこうして~と頭の中でぽんぽんと工程が浮かび、そしてサクッとハマりました。

難しい。。

とにかく試してみる

なぜか出来ない。なぜか出来ない(;´Д`)・・・。
このままだと埒が明かないので1つずつ試していきました。

辿った工程は以下の通りです。

  1. input[type="submit"]の背景色にCSSグラデーション⇒できる
  2. 単色背景とSVG画像を同時に指定⇒できる
  3. グラデーションとSVG画像を背景として同時に指定⇒できる
  4. input要素を指定しているクラスにそのままfillを指定⇒できない
  5. SVGをbefore擬似要素として使用-その1⇒before疑似要素自体が表示されない\(^o^)/
  6. input要素をbutton要素に変更⇒∠( ゚д゚)/・・・?before疑似要素は表示できたがSVG画像の色が変えられない!
  7. 仕方ないのでSVG自体を白くした別ファイルを作る⇒う~ん・・・負けた気がする。
  8. SVGをシンボル化して使いまわす!⇒CSSファイルで色変更が効く!

input[type="submit"]の背景色にCSSグラデーション

HTML
<input type="submit" value="この条件で検索">

このボタンに実装していきます。まずは背景色にCSSグラデーションを指定。

HTML
<input type="submit" value="この条件で検索" class="button test01">

基本的なボタンの形状はbuttonクラスで使い回し、適当にtest01というクラス名で装飾していきます。
記述が長くなるためベンダープレフィックスの指定は割愛しています。

CSS
.button{
	-webkit-appearance: none;
	color: #fff;
	border: none;
	margin: 0 auto;
	padding: 0.5em 5em;
	line-height: 1;
	text-shadow: 0 1px 0 #a44207;
	font-size: 1.2em;
	font-weight: bold;
	border-radius: 20px;
	cursor: pointer;
	position: relative;
	box-shadow: 0 1px 1px rgba(0,0,0,.3) inset,
				0 1px 1px rgba(255,255,255,.3);
}

.test01{
	background: #E48227;
	background: linear-gradient(top, #F29A30 5%, #E48227 50%);
}

うん、できる。

デモ1

単色背景とSVG画像を同時に指定

HTML
<input type="submit" value="この条件で検索" class="button test02">
CSS
.test02{
	background: #E48227 url(./images/si-glyph-magnifier.svg) 15px center no-repeat;
}

グラデーションの指定を消して背景画像としてSVG画像を指定しています。
うん、できる。

デモ2

グラデーションとSVG画像を背景として同時に指定

HTML
<input type="submit" value="この条件で検索" class="button test03">
CSS
.test03{
	background: #E48227 url(./images/si-glyph-magnifier.svg) 15px center no-repeat;
	background: url(./images/si-glyph-magnifier.svg) 15px center no-repeat,
				linear-gradient(top, #F29A30 5%, #E48227 50%);
}

別の背景指定を複数重ねるマルチバックグラウンドの要領で、backgroundプロパティの中でカンマ区切りで指定します。ポイントとしては先に指定している方が重ね順の上側に位置するという点です。
うん、できる。

デモ3

input要素を指定しているクラスにそのままfillを指定

HTML
<input type="submit" value="この条件で検索" class="button test04">
CSS
.test04{
	background: #E48227 url(./images/si-glyph-magnifier.svg) 15px center no-repeat;
	background: url(./images/si-glyph-magnifier.svg) 15px center no-repeat,
				linear-gradient(top, #F29A30 5%, #E48227 50%);
	fill: #fff;
}

できません。
img要素やCSSのbackgroundで読み込まれると画像として扱われてしまい、CSSでの装飾が効かなくなるようです。

デモ4

SVGをbefore擬似要素として使用-その1

HTML
<input type="submit" value="この条件で検索" class="button test05">
CSS
.test05{
	background: #E48227;
	background:linear-gradient(top, #F29A30 5%, #E48227 50%);
}

.test05:before{
	position: absolute;
	display: block;
	content: url(./images/si-glyph-magnifier.svg);
	width: 16px;
	height: 16px;
	left: 20px;
	top: 10px;
	fill: #fff;
}

できません。
どうやらinputやimg、videoなどの置換要素にはbefore、after疑似要素が使えないらしく、無知な私はしばらくハマりました。ということで別の要素で代用する必要があります。

デモ51

SVGをbefore擬似要素として使用-その2

HTML
<button name="button" type="submit" class="button test05">この条件で検索</button>
CSS
.test05{
	background: #E48227;
	background:linear-gradient(top, #F29A30 5%, #E48227 50%);
}

.test05:before{
	position: absolute;
	display: block;
	content: url(./images/si-glyph-magnifier.svg);
	width: 16px;
	height: 16px;
	left: 20px;
	top: 10px;
	fill: #fff;
}

before疑似要素は表示できました。
ただカラーは変えられません。

デモ52

SVGファイル内で直接スタイリング

HTML
<button name="button" type="submit" class="button test06">この条件で検索</button>

SVGをテキストエディタで開いて編集します。

SVG
<svg width="16" height="16" viewBox="0 0 17 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
	<g class="fillWhite">
		<path d="M16,5.954 C16,2.665 13.317,0 10.009,0 C6.698,0 4.016,2.665 4.016,5.954 C4.016,9.241 6.699,11.906 10.009,11.906 C13.317,11.906 16,9.241 16,5.954 L16,5.954 Z M4.934,6.019 C4.934,3.213 7.213,0.943 10.026,0.943 C12.837,0.943 15.114,3.214 15.114,6.019 C15.114,8.823 12.837,11.094 10.026,11.094 C7.213,11.094 4.934,8.822 4.934,6.019 L4.934,6.019 Z"></path>
		<path d="M1.822,15.964 L0,14.142 L4.037,10.104 C4.037,10.104 4.133,10.869 4.617,11.351 C5.099,11.835 5.859,11.927 5.859,11.927 L1.822,15.964 L1.822,15.964 Z"></path>
		<path d="M13.398,5.073 C13.398,5.645 13.838,5.429 13.838,4.634 C13.838,3.264 12.729,2.154 11.359,2.154 C10.562,2.154 10.347,2.593 10.92,2.593 C12.29,2.593 13.398,3.704 13.398,5.073 L13.398,5.073 Z"></path>
	</g>
	<style type="text/css">
		.fillWhite{
			fill: #fff;
		}
	</style>
</svg>

グループ化しているg要素、もしくはpath要素一つ一つにクラスを付けてSVG内でスタイリングしています。これなら色は変えられますが黒いアイコンと白いアイコンを使い分けたい場合は結局SVGファイルを2つ用意することになります。

デモ6

SVGをシンボル化して使いまわす!

HTML
<button name="button" type="submit" class="button test07">
	<svg><use class="fillWhite" xlink:href="#icon01"></use></svg>
この条件で検索
</button>

<svg width="16" height="16" viewBox="0 0 17 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
	<symbol id="icon01">
		<g>
			<path d="M16,5.954 C16,2.665 13.317,0 10.009,0 C6.698,0 4.016,2.665 4.016,5.954 C4.016,9.241 6.699,11.906 10.009,11.906 C13.317,11.906 16,9.241 16,5.954 L16,5.954 Z M4.934,6.019 C4.934,3.213 7.213,0.943 10.026,0.943 C12.837,0.943 15.114,3.214 15.114,6.019 C15.114,8.823 12.837,11.094 10.026,11.094 C7.213,11.094 4.934,8.822 4.934,6.019 L4.934,6.019 Z"></path>
			<path d="M1.822,15.964 L0,14.142 L4.037,10.104 C4.037,10.104 4.133,10.869 4.617,11.351 C5.099,11.835 5.859,11.927 5.859,11.927 L1.822,15.964 L1.822,15.964 Z"></path>
			<path d="M13.398,5.073 C13.398,5.645 13.838,5.429 13.838,4.634 C13.838,3.264 12.729,2.154 11.359,2.154 C10.562,2.154 10.347,2.593 10.92,2.593 C12.29,2.593 13.398,3.704 13.398,5.073 L13.398,5.073 Z"></path>
		</g>
	</symbol>
</svg>

使いまわすベースとなるSVGのsvgタグ内をsymbol要素で囲むことでこのSVGを参照できるようになります。symbol要素には参照名としてidを付けておきます(classだとダメ)。

使いまわすベースとなるSVGをHTMLファイルにインラインで記述する必要がありますが、通常通りCSSでスタイリングできるため複数のSVGファイルを用意する必要がなくなるメリットがあります。

デモ7

管理人「よら」はこう思う

最後のSVGを参照する方法はCSSファイルでの操作ができるので非常に使いやすい方法だと思います。
ただ、ベースとなるSVGはUI的には不必要な要素なのでCSSで非表示にしている点がSEO的にあまり気持ちよくないんですよね。

表示するだけならIE9以上で使えますし、選択肢の1つとして覚えておこうと思います。