svgアイコンをcssで指定する方法

SVGアイコンをCSSで指定する方法

画面右下のトップに戻るボタン を例に,SVGをCSSで指定する方法の自分用備忘録.

何の経験も知識もないド素人が,このブログを少しでも良くしたいとの思いだけで,その都度必要なことを調べたり自分で手を動かしたりした内容を忘れないように書いているだけです.

ちゃんと技術書を読んで仕様の勉強をしたわけではないので間違った表現やワケわかってないところが多々あります.

コピペは自由ですが,ちゃんとこういうの↓も参考にして,自己責任でお願いします・・・

CSS設計完全ガイド
本書は,CSSのさまざまな設計手法を紹介しつつ,基礎から実践のポイントまで解説します.

間違った表現等気になる部分がありましたら,お問合せからこっそり(笑)教えてもらえると勉強になります.

普段は肌断食とか節約について書いている人です.

CSSか?SVGか?fontawesomeか?

トップに戻るボタンみたいな単純な図形であれば,CSSでそのまま書いてしまうこともできるけど,中を切り抜いたような表現をCSSだとどうしたらいいのか(そもそもできるのかどうかすら)わからない.

こう じゃなくて

こう したい

ってこと.

全体的に透けてるんじゃなくて,中は切り抜きたい.

俺の微妙なこだわり(笑)

だからCSSではなくSVGにした.

あと,CSSでそのまま描いた方がSVGよりファイルサイズが小さくなるのかというと,それは一概にそうとも言えない.

単純なSVGファイルは記述も短くて軽いから,場合によってはCSSより軽くなることもあった.

だったら,くり抜いたり複雑にしたりとinkscapeで自由にデザインできるSVGに統一した方が管理もしやすくていいかなと思っているけど,まあ場合によってはCSSでデザインするのもありかもとも思ったり.

今のところは全部SVGを使っている.←追記:スマホ画面左上のハンバーガーメニューはCSSに変えた.

fontawesomeは読み込みに負荷がかかるので,バージョンアップしたタイミングで使っているアイコンを全部SVG化して導入をやめた.

数えるほどしかアイコン使っていないのに,無数のアイコンをわざわざ読み込む必要なし.

SVGイメージのURLについて

CSSで指定する場合はURL(ここにSVGイメージのURL);という形で記述するけど,このURLにもいくつか記述方法がある.

外部ファイルURLの場合

そのままURLを書き込めばOK.

例:

URL("https://orery-blog.github.io/files/svg/chevron-circle-up.svg");

dataURLの場合

今のところ俺はこの方法で統一するつもり.

直接書き込んだ方が読み込みに行かないぶん動作が軽くなるから.

書き方としては,

url("data:image/svg+xml,SVGファイルの中身");

こんな感じ.

ポイントは2つ.

ポイント1
SVGのコードをURLエンコードする.

このSVGファイルの中身だけど,本当にそのままそっくりタグ付きのまま書き込んで,エンコードも何もしなくてもプレビュー表示はできたりする.

でも,アップロードしたら表示されてなかった.

あと,プレビュー表示でも,色指定のfillを追加したら#があると表示されなかった.

色の名前で書き込めば#使わないからちゃんとその色で表示された.

例:#fff(エンコード後は%23fff) → white(エンコード後もwhite)

SVGの中身は画像と違ってバイナリデータではなくてxmlで書かれているから,プレビュー表示ではうまく行くのかな?わかんない.

URLエンコードをしておくと無難だと思うのでしておく.

エンコードしない方がサイズは小さいけどね.

#は3倍の%23になるし.

ポイント2
クォート内で同じクォートを利用するときは、エスケープする必要がある

URL全体を囲んでるやつと,URLの中で囲んでるやつは同じだとうまくいかない.

どういうことかというと,content:url(" 中身 ");の場合,中身の中に「"」があるとうまくいかない.

うまくいかない例:

url("data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"%3E%3Cpath d="M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z"/%3E%3C/svg%3E");

うまくいく例(パターン1):

url("data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"%3E%3Cpath d=\"M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z\"/%3E%3C/svg%3E");

うまくいく例(パターン2):

url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'/%3E%3C/svg%3E");

つまり,クォート内でクォートを利用するときは,エスケープするか,もしくは違うクォートを使えば問題ない.

エスケープする場合
  • シングルクォート(')内のシングルクォート(')はエスケープ(\')する
  • ダブルクォート(")内のダブルクォート(")はエスケープ(\")する
違うクォートを使う場合
  • シングルクォート(')内はダブルクォート(")にする
  • ダブルクォート(")内はシングルクォート(')にする

※¥と\が混在しているかもしれませんが,同じものです.

前置き長かったな.

ということで以下実際にCSSに書く方法.

これ以降出てくるCSSの使用例は全て,見た目はまったく同じ表示になる.

つまりhtmlで<div class="page_top"/>と書くと,画面右下にトップに戻るボタン が表示される.

contentを使う

contentでSVGイメージを指定しても,background-imageでSVGイメージを指定しても,挙動がほとんど同じだった.

違いがあったとすれば,サイズ指定の仕方によっては,background-imageで指定した場合はSVGイメージの繰り返しが起きた.

contentで指定した場合は繰り返しは起きない.

そもそもSVGアイコンを使いたいときって繰り返して使いたい事なんてないだろうからcontent使えばいいかなと思うけど,background-imageの繰り返しはbackground-repeat:no-repeatで消せるから,汎用性や意味合い的なことを考えれば,background-imageを使う方が自然な気はしている.

直接contentに指定する場合

メリット
  • CSS短い
  • 疑似要素の空きがある
デメリット
  • 色を変えられない
  • htmlで記述したものが表示されない

htmlで記述したものが表示されないって言うのは,例えば,

<div class="page_top">hoge</div>

と記述したとして,page_topクラスを付与したタグで囲んだhogeは表示されない.

hogeが表示されるようにするには後述する疑似要素を使う.

なお,色は変えられないけど,opacityは効く.

色を変える場合は,SVGのURLの中に直接色を指定するコードを入れるか,後述するmask-imageで指定する.

使用例:

.page_top{
    content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%233fefee' opacity='.6' d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'/%3E%3C/svg%3E");
    position: fixed;
    width: 50px;
    height: 50px;
    right: 0;
    bottom: 0;
}

この例のパターンではopacityはSVGの中身(path)で指定したけど,positionとかと並べて指定しても効く.

疑似要素で指定する場合

メリット
  • CSS短い
  • htmlで記述したものが表示できる
デメリット
  • 色を変えられない
  • サイズが変えられないことがある?

SVGではなく画像ファイルだと,外部URLの場合は疑似要素の時はサイズの指定が効かなくなった.

background-imageでも画像の場合はなんかサイズ指定うまくできない.

でもSVGは外部URLでもサイズ指定できそう.

よくわからない.

まあ外部URLも画像も使わないからいいや.

使用例:

.page_top::before{
    content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%233fefee' opacity='.6' d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'/%3E%3C/svg%3E");
    position: fixed;
    width: 50px;
    height: 50px;
    right: 0;
    bottom: 0;
}

background-imageを使う

contentを使った時とほとんど同じ.しいて言うなら

メリット
無難そうなところ?笑
デメリット
疑似要素ではcontent:'';の記述を忘れがち

直接background-imageに指定する場合

さっきcontentって書いてたところをそっくりそのままbackground-imageに変えるだけ.

使用例:

.page_top{
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%233fefee' opacity='.6' d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'/%3E%3C/svg%3E");
    position: fixed;
    width: 50px;
    height: 50px;
    right: 0;
    bottom: 0;
}

疑似要素を使う場合

content:'';を追加するのを忘れない.

使用例:

.page_top::before{
    content:'';
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%233fefee' opacity='.6' d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'/%3E%3C/svg%3E");
    position: fixed;
    width: 50px;
    height: 50px;
    right: 0;
    bottom: 0;
}

mask-imageを使う

すごい便利がいいしオールマイティに使えそうだから,以前は全部この書き方にしてた.

contentでもbackground-imageでもひっかかってた画像のサイズとかもちゃんと指定できるし.

でも,mask-imageはベンダープレフィックス(-webkitとか接頭辞がつくやつ)が必要なせいで無駄に複数回SVGのデータを書き込むことになってメンテナンス性が悪いし,俺別に外部URL使ってないし,場所によって色を変えたい時っていうのが今のところないので結局今はこの方法はあんまり使ってない.

なおこれもbackground-image同様SVGイメージの繰り返しが起きる.

メリット
  • background-colorで色を変えられる
  • 外部URLでも色が変えられる
デメリット
  • ベンダープレフィックスつけるとCSSが極端に長くなる

どれだけ長くなるかわかりやすいように右端で折り返してみた↓

使用例:

.page_top{
    position: fixed;
    width: 50px;
    height: 50px;
    right: 0;
    bottom: 0;
    background-color: rgba(63, 239, 238,.6);
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'/%3E%3C/svg%3E");
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'/%3E%3C/svg%3E")
}

今は-webkitをひとつプラスするだけで良さそうだけど,少し前までは-oとか-msとかもっとたくさん記述しないといけなかったから,まあマシにはなったけど.

background-colorで色指定できるのは便利(SVGの中身いちいち書き換えなくていい)だから,mask-imageが完全に標準化したらまた戻すかも.

疑似要素の場合

background-imageの時と同じく,content:'';を忘れない.

使用例:

.page_top::before {
    content: '';
    position: fixed;
    width: 50px;
    height: 50px;
    right: 0;
    bottom: 0;
    background-color: rgba(63, 239, 238,.6);
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'/%3E%3C/svg%3E");
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'/%3E%3C/svg%3E")
}

まとめ

簡単にまとめ.
CSSでSVGを指定する方法
  • dataURLの場合はSVGをURLエンコードする
  • →クォート内では同じクォートを使わない
  • SVGのpathに直接色を記述してcontentかbackground-imageでURL指定する
  • →色を自由に変えたいときはmask-imageを使う

ちなみに現時点ではこのトップに戻るボタン は,CSSで指定せずにhtmlに書いてます.

(今日この記事で使いまわすことになったから・・・笑)

このデザインでしかこのアイコンは使わないって場合にはCSSで指定しちゃうのがhtml書くのも簡単で楽な気がしています.

今回で言えば,htmlに<div class="page_top"/>って書くだけですから.

\ この記事をシェアする /

関連記事