SVG画像にCSS変数を適用、D3.js制御

SVG画像はベクター画像標準としてWebで広く利用されています。
またSVGはXMLでもあり、加工するとCSS変数も利用できます。これにより、用途に応じて色を変えられる画像を作れます。

CSS変数を用いるためのインクルード形式

SVG画像を表示するタグは複数あり、一般的なimgタグでインクルードした場合には画像内の制御はできません。

<!-- 通常のインクルード -->
<img src="sample.svg" />

<!-- CSS変数が効くインクルード -->
<svg style="--img-color: blue">
  <use href="sample.svg#img" />
</svg>

ただし、useタグでインクルードするためには、svgファイルを書き換える必要があります。
変更したファイルは、Inkscapeなど一部のアプリで編集できない形式になります。

useタグでインクルードできるsvgマークアップ

useタグはSVG画像内のsvg > defs > symbolを参照します。
多くの画像編集ソフトはdefsやsymbolを含まない形式で直接gやpathを書き出すため、テキストエディタでタグを追加します。

また、defsタグ内はレンダリングされないため、svgファイル内にもuseタグを追加しておくと、<img />でもインクルードできる形式になります。
以下のような構造になります。

<svg>
  <!-- 一般的な画像としても表示可能にするためuseを追加 -->
  <use href="#img" />

  <!-- useタグ用に defs と symbol でラップ -->
  <defs>
    <symbol id="img" viewBox="0 0 200 100">
      <!-- 画像編集ソフトが出力した画像データ -->
      <g>
        <!-- 外部から制御したい部分をCSS変数に置き換え -->
        <path fill="var(--img-color, #888888)" />
      </g>
    </symbol>
  </defs>
</svg>

g > pathの部分が画像で、色などは各描画要素に指定されています。
CSS変数を利用したい場合には、テキスト置換で色を変数に置き換えます。 CSS変数 は第2引数を指定でき、元の色を設定しておくと<img />タグなどでインクルードした際にフォールバックで使われます。

なお、viewBox属性は多くの場合svgタグに記載されていますが、symbolに移しておいた方が使いやすいでしょう。

D3.js

SVGフォーマットの画像は、画像ファイルであると同時にXMLドキュメントでもあり、プログラムで生成することも可能な形式です。

D3.js はJavascriptのSVG描画ライブラリで、主にグラフデータをもとに座標計算して画像を生成できます。

D3.jsで利用する主なSVG要素には以下のようなものがあります。

  • rect
  • circle
  • text
  • line

要素の修飾はアトリビュートがメイン

HTML要素の修飾はおおむねCSSを利用してstyleアトリビュート(属性)に指定しますが、SVGの場合は主な修飾は個別のアトリビュートに指定します。

たとえば、rectの場合は座標をx, y, width, height属性で指定します。

また、色の指定はSVG特有のfill属性に指定します。色の値はCSSと同様のRGB16進カラーコードやキーワードを利用可能です。

D3.jsにはアトリビュート操作関数としてattr()、CSS操作関数としてstyle()が用意されています。

テキストの色指定と配置は独特

SVG内のtext要素の色もCSSのcolorではなく、fill属性で指定します。また背景色は設定できず、別のrect要素を背面に置くことになります。

テキストの配置には、横配置の text-anchor と縦配置の dominant-baseline 属性をそれぞれ使う機会があります。

SVG内の要素ごとにCSS制御可能

D3.jsを利用する用途では、1つのSVGファイル内に多数のcircleやrectを描画することになりますが、各要素ごとに表示・非表示や色変更などの操作が可能です。

HTML同様、各要素にid属性やclass属性を指定可能なため、通常のCSSによる制御と同様の方法で、SVGファイル外からCSSのスタイル定義を適用できます。

また、SVG独特の要素に g というグルーピングのための要素があり、g.some_class rectのような形式でレイヤとして操作できます。

イベントをハンドルしないattribute

SVG内の要素にUIイベントを設定した場合にも、その要素のうえに別の要素があるとイベントが動作しません。

opacity=0を指定して非表示にしている場合でも上の要素が操作イベントを取得してしまいます。

上から重なる要素にpointer-events='none'アトリビュートを指定することで下層の要素のイベントを動作させられます。
SVGの上下関係は描画の前後で決まるため、注意が必要です。

⁋ 2021/10/10↻ 2026/10/08