SVGの色を変更する方法

JavaScript

SVGの色を変更する

maskとして利用し、background-colorを透過する

簡単にできて実用性の高い方法です。

.menuButton::before{
    content: "";
    display: block;
    width: 120px;
    height: 120px;
    background-color: red;
    -webkit-mask-image: url("./img/circle.svg");
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    -webkit-mask-size: contain;
}

私はelectron開発中なのでwebkitのprefixを付けていますが、必要ない場合はprefix省いてください。
上記のように::before, ::after疑似要素にmask-imageとして利用すればほぼcssのみで完結できます。

疑似要素はDOM要素ではないためJavascriptからは触れません。そのため疑似要素でmaskするとクラスの付与で色を変えるのが面倒になります。なので疑似要素にせず、適当なDOMを表示領域に被せてしまうのが吉。そのDOMに以下のようなclassを付与すると簡単に色変更ができます。

.--blue{
  background-color: blue;
}

javascript側でbackground-imageを設定する際に改変する

私が書きたかったのはこっち。
表示するSVGを動的に入れ替えたり、都度色を変更したい場合があります。

SVGをjavascriptでbackground-imageに設定するには以下のようにします。

let iconURL = `url(./img/${iconName}.svg)`;
targetDOM.style.backgroundImage = iconURL;

ただし、これだとSVGの色は変更できません。
通常のブラウザ開発ならサーバ再度でごにょごにょします。
私はElectron開発なのでnode.jsです。

let svgPath = path.resolve(__dirname, './img/iconName.svg')
let svgString = fs.readFileSync(svgPath, 'utf-8');
let cutKey = '<svg ';
let arr = svgString.split(cutKey);
let preEncodeSVG = cutKey + arr[1];  

svgファイルから必要な箇所(“<svg ~ /svg>)を切り出しています。
往々にしてファイルの前半には不要な文字列が付いているのでsplitで”<svg”が出てくるところで分割し、後半部分だけ利用します。

let regExp = new RegExp('fill=\"#[0-9a-fA-F]{6}\"', 'i')
;
let colorChangedSVG = preEncodeSVG.replace(regExp, 'fill="#128400"')
;

let encodedSVG = Buffer.from(replaced).toString('base64');  // node.jsでやる場合
let encodedSVG = window.btoa(colorChangedSVG);              // brower側でやる場合

targetDOM.style.backgroundImage = "url(data:image/svg+xml;base64," + encodedSVG  + ")";

そしてsvgタグ内でfillしている部分を正規表現で入れ替えます。
上のコードは手抜きなのでカラーコードが#000000と6桁で指定されていること前提です。
割と3桁(#FFF)指定されていることが多いので実際に使う場合は改変してください。

色が変更出来たらbase64形式にエンコードします。
node.jsでやる場合はBufferを、ブラウザ側でやる場合はwindow.btoa()メソッドでエンコードします。btoa(Binary to Ascii ?)でなく、encodeURI()やencodeURIComponent()でエンコードしても良いようです。
その場合は”url(data:image/svg+xml;base64,”の部分が”url(data:image/svg+xml;utf8,”になるみたいです。encodeURIは#を変換しないため、エンコード後に’%23’に追加でreplaceする必要があります。

とはいえbtoa()以外は私が試したらなぜかうまく表示できなかったので、これで合ってるかは知りません。

コメント