SCSSでbackgroundにsvgを指定するときに便利なbase64エンコード関数を作る
IE9で linear-gradient を使いたいとき、IE独自の filter では実現不可能なものがあります。color stop がないため、他のブラウザと比べて表現できる範囲がせまいのです。そこで、IE9のみSVGで代用するためにSVGコードからbase64エンコードして埋め込むmixinを作ったので紹介します。
アルゴリズム
アルゴリズムはこちらを参考にさせていただきました。非常に分かりやすかったです。
base64Encode関数
@function base64Encode($string)
{
// 文字から2進数に変換するテーブル
$character_to_binary_number_table:
(
' ': '00100000', '!': '00100001', '"': '00100010',
'#': '00100011', '$': '00100100', '%': '00100101',
'&': '00100110', '\'': '00100111', '(': '00101000',
')': '00101001', '*': '00101010', '+': '00101011',
',': '00101100', '-': '00101101', '.': '00101110',
'/': '00101111', '0': '00110000', '1': '00110001',
'2': '00110010', '3': '00110011', '4': '00110100',
'5': '00110101', '6': '00110110', '7': '00110111',
'8': '00111000', '9': '00111001', ':': '00111010',
';': '00111011', '<': '00111100', '=': '00111101',
'>': '00111110', '?': '00111111', '@': '01000000',
'A': '01000001', 'B': '01000010', 'C': '01000011',
'D': '01000100', 'E': '01000101', 'F': '01000110',
'G': '01000111', 'H': '01001000', 'I': '01001001',
'J': '01001010', 'K': '01001011', 'L': '01001100',
'M': '01001101', 'N': '01001110', 'O': '01001111',
'P': '01010000', 'Q': '01010001', 'R': '01010010',
'S': '01010011', 'T': '01010100', 'U': '01010101',
'V': '01010110', 'W': '01010111', 'X': '01011000',
'Y': '01011001', 'Z': '01011010', '[': '01011011',
'\\': '01011100', ']': '01011101', '^': '01011110',
'_': '01011111', '`': '01100000', 'a': '01100001',
'b': '01100010', 'c': '01100011', 'd': '01100100',
'e': '01100101', 'f': '01100110', 'g': '01100111',
'h': '01101000', 'i': '01101001', 'j': '01101010',
'k': '01101011', 'l': '01101100', 'm': '01101101',
'n': '01101110', 'o': '01101111', 'p': '01110000',
'q': '01110001', 'r': '01110010', 's': '01110011',
't': '01110100', 'u': '01110101', 'v': '01110110',
'w': '01110111', 'x': '01111000', 'y': '01111001',
'z': '01111010', '{': '01111011', '|': '01111100',
'}': '01111101', '~': '01111110'
);
// 2進数からbase64の文字に変換するテーブル
$binary_number_to_base64_table:
(
'000000': 'A', '000001': 'B', '000010': 'C', '000011': 'D',
'000100': 'E', '000101': 'F', '000110': 'G', '000111': 'H',
'001000': 'I', '001001': 'J', '001010': 'K', '001011': 'L',
'001100': 'M', '001101': 'N', '001110': 'O', '001111': 'P',
'010000': 'Q', '010001': 'R', '010010': 'S', '010011': 'T',
'010100': 'U', '010101': 'V', '010110': 'W', '010111': 'X',
'011000': 'Y', '011001': 'Z', '011010': 'a', '011011': 'b',
'011100': 'c', '011101': 'd', '011110': 'e', '011111': 'f',
'100000': 'g', '100001': 'h', '100010': 'i', '100011': 'j',
'100100': 'k', '100101': 'l', '100110': 'm', '100111': 'n',
'101000': 'o', '101001': 'p', '101010': 'q', '101011': 'r',
'101100': 's', '101101': 't', '101110': 'u', '101111': 'v',
'110000': 'w', '110001': 'x', '110010': 'y', '110011': 'z',
'110100': '0', '110101': '1', '110110': '2', '110111': '3',
'111000': '4', '111001': '5', '111010': '6', '111011': '7',
'111100': '8', '111101': '9', '111110': '+', '111111': '/'
);
// 文字列を2進数へ変換したときに代入する変数
$binary_number: '';
// 文字列の長さだけループ
@for $i from 1 through str-length($string)
{
// 1文字ずつ取り出す
$character: str-slice($string, $i, $i);
// 2進数へ変換
$binary_number: $binary_number + map-get($character_to_binary_number_table, $character);
}
// 2進数を6ビットずつ分割した配列
$hexadecimal_number: ();
// 2進数を6ビットずつ分割した配列の長さ
$hexadecimal_length: ceil(str-length($binary_number)/6-1);
@for $i from 0 through $hexadecimal_length
{
// 6ビットに区切った文字列
$tmp: str-slice($binary_number, 2*($i*3)+1, (2*($i*3)+1+5));
// 配列の最後のビット数が6とは限らないのでチェック
@if $i == $hexadecimal_length
{
// 6ビットに区切った文字列の長さ
$tmp_length: str-length($tmp);
// 6ビットでないとき
@if $tmp_length != 6
{
// 0で埋めて6ビットにする
@for $j from $tmp_length+1 through 6
{
$tmp: $tmp + '0';
}
}
}
// 2進数を6ビットずつ分割
$hexadecimal_number: append($hexadecimal_number, $tmp);
}
// base64に変換した文字列
$base64_string: '';
@for $i from 1 to length($hexadecimal_number)+1
{
// 変換テーブルを使ってbase64エンコード
$base64_string: $base64_string + map-get($binary_number_to_base64_table, nth($hexadecimal_number, $i));
}
// base64の最終結果
$base64: '';
// 4ビットずつ分割した配列の長さ
$fourdecimal_length: ceil(str-length($base64_string)/4-1);
@for $i from 0 through $fourdecimal_length
{
// 4ビットに区切った文字列
$tmp: str-slice($base64_string, 2*($i*2)+1, (2*($i*2)+1+3));
// 配列の最後のビット数が4とは限らないのでチェック
@if $i == $fourdecimal_length
{
// 4ビットに区切った文字列の長さ
$tmp_length: str-length($tmp);
// 4ビットでないとき
@if $tmp_length != 4
{
// =で埋めて4ビットにする
@for $j from $tmp_length+1 through 4
{
$tmp: $tmp + '=';
}
}
}
$base64: $base64 + $tmp;
}
@return $base64;
}
使い方
html
{
background: url('data:image/svg+xml;base64,' + base64Encode(''));
}
こんな感じで直接SVGコードを指定できます。base64Encode() 関数に渡すときは改行は消して1行のSVGコードにしておきましょう。