不能正常显示svg的解决方案

原本用data:img/svg+xml;utf-8,<svg …. 这种写法,将svg作为css引入的背景图,既矢量,又能比base64更小,本来是不错的方案。但升级到最新Chrome (72.0.3626.109) 发觉竟不能正常显示了。

Google一翻,在Stackoverflow 找到了原因及解决方案:需要将<svg/> 转换为URL编码(URL encode)。也即原来的写法,
[cc lang=”css”]data:image/svg+xml;utf8,<svg width=”40″ height=”38″ xmlns=”http://www.w3.org/2000/svg”><g fill=”#C7D5FF” fill-rule=”evenodd”><path d=”M28.804 11.071h9.827a1.321 1.321 0 1 1 .001 2.642h-10.98L21.26 36.525a1.343 1.343 0 0 1-.125.3 1.319 1.319 0 0 1-1.158.668 1.345 1.345 0 0 1-1.159-.67 1.319 1.319 0 0 1-.133-.332L12.3 13.713H1.321a1.321 1.321 0 1 1 0-2.642h9.838L6.792 2.415a1.316 1.316 0 0 1 .6-1.773 1.337 1.337 0 0 1 1.784.591l4.268 8.46 5.351-8.488A1.335 1.335 0 0 1 20.682.7c.19.117.345.278.453.468l5.373 8.523 4.266-8.459a1.337 1.337 0 0 1 1.795-.59 1.316 1.316 0 0 1 .6 1.773l-4.365 8.656zm-8.829-6.756l-4.257 6.756h8.516l-4.259-6.756zm-4.908 9.398l4.91 17.524 4.91-17.524h-9.82z”/><path d=”M18.924 36.983L.269 13.2a1.312 1.312 0 0 1-.078-1.511L6.854 1.124A1.336 1.336 0 0 1 7.984.5h23.985c.458 0 .885.234 1.13.621l6.663 10.568c.296.47.265 1.075-.078 1.511L21.029 36.982a1.339 1.339 0 0 1-2.105.001zM2.945 12.309l17.032 21.71 17.032-21.71-5.778-9.164H8.722l-5.777 9.164z”/></g></svg>[/cc]

需要改成:
[cc lang=”css”]data:image/svg+xml;utf8,<svg%20width%3D”40″%20height%3D”38″%20xmlns%3D”http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg”><g%20fill%3D”%23C7D5FF”%20fill-rule%3D”evenodd”><path%20d%3D”M28.804%2011.071h9.827a1.321%201.321%200%201%201%20.001%202.642h-10.98L21.26%2036.525a1.343%201.343%200%200%201-.125.3%201.319%201.319%200%200%201-1.158.668%201.345%201.345%200%200%201-1.159-.67%201.319%201.319%200%200%201-.133-.332L12.3%2013.713H1.321a1.321%201.321%200%201%201%200-2.642h9.838L6.792%202.415a1.316%201.316%200%200%201%20.6-1.773%201.337%201.337%200%200%201%201.784.591l4.268%208.46%205.351-8.488A1.335%201.335%200%200%201%2020.682.7c.19.117.345.278.453.468l5.373%208.523%204.266-8.459a1.337%201.337%200%200%201%201.795-.59%201.316%201.316%200%200%201%20.6%201.773l-4.365%208.656zm-8.829-6.756l-4.257%206.756h8.516l-4.259-6.756zm-4.908%209.398l4.91%2017.524%204.91-17.524h-9.82z”%2F><path%20d%3D”M18.924%2036.983L.269%2013.2a1.312%201.312%200%200%201-.078-1.511L6.854%201.124A1.336%201.336%200%200%201%207.984.5h23.985c.458%200%20.885.234%201.13.621l6.663%2010.568c.296.47.265%201.075-.078%201.511L21.029%2036.982a1.339%201.339%200%200%201-2.105.001zM2.945%2012.309l17.032%2021.71%2017.032-21.71-5.778-9.164H8.722l-5.777%209.164z”%2F><%2Fg><%2Fsvg>[/cc]

进阶解决方案

国外小伙对于sass处理URL encode写了一个很赞的function, 完美。
[cc lang=”css”]
// Replace letters
@function str-replace($string, $search, $replace: ”) {
$index: str-index($string, $search);

@if $index {
@return str-slice($string, 1, $index – 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}

@return $string;
}

// Encode symbols
@function url-encode($string) {
$map: (
“%”: “%25”,
“<": "%3C", ">“: “%3E”,
” “: “%20”,
“!”: “%21”,
“*”: “%2A”,
“‘”: “%27”,
‘”‘: “%22”,
“(“: “%28”,
“)”: “%29”,
“;”: “%3B”,
“:”: “%3A”,
“@”: “%40”,
“&”: “%26”,
“=”: “%3D”,
“+”: “%2B”,
“$”: “%24”,
“,”: “%2C”,
“/”: “%2F”,
“?”: “%3F”,
“#”: “%23”,
“[“: “%5B”,
“]”: “%5D”
);

$new: $string;

@each $search, $replace in $map {
$new: str-replace($new, $search, $replace);
}

@return $new;
}

// Format the SVG as a URL
@function inline-svg($string) {
@return url(‘data:image/svg+xml,#{url-encode($string)}’);

[/cc]
> github url

再进一步

张鑫旭博文介绍,不用全部标点都转码,只需要将关键的几个转换即可正常显示,部分转码可使文件更小,故优化方案如下,实践可行。

[cc lang=”css”]
// Replace letters
@function str-replace($string, $search, $replace: ”) {
$index: str-index($string, $search);

@if $index {
@return str-slice($string, 1, $index – 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}

@return $string;
}

// Encode symbols
@function url-encode($string) {
$map: (
“%”: “%25”,
“<": "%3C", ">“: “%3E”,
“!”: “%21”,
“*”: “%2A”,
“‘”: “%27”,
‘”‘: “%22”,
“#”: “%23”);

$new: $string;

@each $search, $replace in $map {
$new: str-replace($new, $search, $replace);
}

@return $new;
}

// Format the SVG as a URL
@function inline-svg($string) {
@return url(‘data:image/svg+xml,#{url-encode($string)}’);

[/cc]