svgのCSS埋め込み私的メモ 何をエンコードすれば良い？

## はじめに

何の文字をエンコードすればいいのか調査してみた

正しくsvgの何の文字をエンコードすればいいのか、ぐぐっても、どくっても、出てこないのもありました。

## 前提

以下のようなperlコードにおいて外部ファイル化したSVGを自動で埋め込むこととする

```svgfont.pl
print <<EOM;
.icon-twitter-white {
	background: url('@{[&svg("icon-twitter.svg","#000","#fff")]}') no-repeat center;
}

.icon-twitter-black {
	background: url('@{[&svg("icon-twitter.svg","#000","#000")]}') no-repeat center;
}

EOM
```

なお、今回使用するSVGアイコンは以下となります
```icon-twitter.svg
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 48 48"><path fill="#000" d="M34.87 7.86v1c0 10.53-8 22.67-22.67 22.67A22.49 22.49 0 0 1 0 28a15 15 0 0 0 1.9.12 16 16 0 0 0 9.89-3.42 8 8 0 0 1-7.44-5.54A8 8 0 0 0 8 19a8 8 0 0 1-6.4-7.81v-.11a7.93 7.93 0 0 0 3.62 1A8 8 0 0 1 2.7 1.45a22.63 22.63 0 0 0 16.43 8.33 8 8 0 0 1 13.58-7.27A16 16 0 0 0 37.77.58 8 8 0 0 1 34.26 5a15.82 15.82 0 0 0 4.58-1.26 16.24 16.24 0 0 1-3.97 4.12Z"/></svg>
```

## 最初は

開発時、base64なら確実であったのもあるので、めんどくさいので base64でエンコードを行っていました

```svgfont.pl
sub svg {
	my($svg,$before,$after)=@_;
	my $ret=`cat $svgsrc/$svg|sed -e 's/$before/$after/g'| base64 | sed -z 's/\\n//g'`;
	return "data:image/svg+xml;base64," . $ret;
}
```

## 実質上のUS-ASCIIで埋め込む
CSSに埋め込むにあたってここが苦労しました。
base64であればすべての文字が肥大化しますので格段に容量が増えますが
US-ASCIIで埋め込めば最小限の文字列ですみます。

```svgfont.pl
sub svg {
	my($svg,$before,$after)=@_;
	my $ret=`cat $svgsrc/$svg|sed -e "s/'/\\\'/g" | sed -e 's/"/\\\"/g' |sed -e 's/ /%20/g'| sed -e 's/$before/$after/g'| sed -e 's/#/%23/g'|sed -z 's/\\n//g'`;
	return "data:image/svg+xml," . $ret;
}
```

＄before、＄after はただの色置換です。
置換する必要がなければ、同じ値をいれておきます

:::note info
また、そう大して負荷がかかるわけではないが、base64をデコードするより、％をデコードするほうのが、CPU的には優しいのかもしれません
:::

URLに記載される :// もエンコードしている例もありますが
エンコードする必要がありませんでした。

＃ の文字はエンコードしないと使い物にならないのは知っていましたが
以外と「 」（半角スペース）をエンコードしないとだめだったわけです

また、マルチバイト文字が入るわけではないことを前提としていますので、;utf8 の記載は節約しています

生成されたCSS
```icon-twiter.css
.icon-twitter-white {
	background:url('data:image/svg+xml,<svg%20xmlns="http://www.w3.org/2000/svg"%20version="1.1"%20viewBox="0%200%2048%2048"><path%20fill="%23fff"%20d="M34.87%207.86v1c0%2010.53-8%2022.67-22.67%2022.67A22.49%2022.49%200%200%201%200%2028a15%2015%200%200%200%201.9.12%2016%2016%200%200%200%209.89-3.42%208%208%200%200%201-7.44-5.54A8%208%200%200%200%208%2019a8%208%200%200%201-6.4-7.81v-.11a7.93%207.93%200%200%200%203.62%201A8%208%200%200%201%202.7%201.45a22.63%2022.63%200%200%200%2016.43%208.33%208%208%200%200%201%2013.58-7.27A16%2016%200%200%200%2037.77.58%208%208%200%200%201%2034.26%205a15.82%2015.82%200%200%200%204.58-1.26%2016.24%2016.24%200%200%201-3.97%204.12Z"/></svg>') no-repeat center;
}

.icon-twitter-black {
	background:url('data:image/svg+xml,<svg%20xmlns="http://www.w3.org/2000/svg"%20version="1.1"%20viewBox="0%200%2048%2048"><path%20fill="%23000"%20d="M34.87%207.86v1c0%2010.53-8%2022.67-22.67%2022.67A22.49%2022.49%200%200%201%200%2028a15%2015%200%200%200%201.9.12%2016%2016%200%200%200%209.89-3.42%208%208%200%200%201-7.44-5.54A8%208%200%200%200%208%2019a8%208%200%200%201-6.4-7.81v-.11a7.93%207.93%200%200%200%203.62%201A8%208%200%200%201%202.7%201.45a22.63%2022.63%200%200%200%2016.43%208.33%208%208%200%200%201%2013.58-7.27A16%2016%200%200%200%2037.77.58%208%208%200%200%201%2034.26%205a15.82%2015.82%200%200%200%204.58-1.26%2016.24%2016.24%200%200%201-3.97%204.12Z"/></svg>') no-repeat center;
}

```

:::note info
しかしなんでsedを使ったのかはわかりません
:::

## 苦労した理由

svgはXMLなので書式にエラーがあればエラーを出すはずですが、

誤って生成したものをCSSに埋め込むとただ真っ白になるだけ。

かつ、誤って生成したエンコード済のdataスキーマのURLをブラウザに貼り付けても正常に表示されるため


```error.svg
<svg><path fill="></svg>
```

ためしに100%エラーの出るsvgを上記に記載しましたが、
これが &lt;img src= で読み込まれていたとしても
エラーが出ない理屈と同じなわけです

## 結論

CSSに埋め込むSVGは、マルチバイト文字がなければ、「#」と「 」（半角スペース）をエンコードすれば良い