構造と座標系

SVG のviewBox / preserveAspectRatio / 座標系。これが分かるかどうかで SVG 体験は天と地。

SVG ルート要素

<svg
  xmlns="http://www.w3.org/2000/svg"
  width="200"
  height="100"
  viewBox="0 0 200 100"
  preserveAspectRatio="xMidYMid meet"
  role="img"
  aria-label="..."
>
  ...
</svg>

2 つの座標系

viewBox="0 0 200 100" でも width="400" height="200" にすると
内部の座標は 0〜200 / 0〜100 のまま、表示は 2 倍に拡大される。
      

viewBox の構文

viewBox="min-x min-y width height"

例: viewBox="0 0 100 100"        100x100 の座標系
   viewBox="-50 -50 100 100"    中心が原点になる
   viewBox="0 0 200 100"        200x100 の長方形

座標系のルール

(0,0) ─────→ x
  │
  │
  │
  ▼
  y
      

preserveAspectRatio

viewBox の比率と width/height の比率がズレた時の挙動を決める。

preserveAspectRatio="xMidYMid meet"
                     └────────┘ └──┘
                     アライン    フィット方式

アライン

意味
none比率を無視して引き伸ばす
xMinYMin左上に寄せる
xMidYMid中央に寄せる(既定)
xMaxYMax右下に寄せる
xMinYMid 等の組合せX / Y を別々に

フィット方式

SVG の主要な構造要素

要素用途
<svg>ルート(ネスト可)
<g>グループ化(座標変換やスタイル継承)
<defs>再利用可能な定義(gradient / pattern / symbol)
<use>defs / symbol を参照して描画
<symbol>再利用部品(viewBox を持てる)
<title>ツールチップ・アクセシビリティ
<desc>長い説明(A11y)
<clipPath>クリッピング
<mask>マスク
<style>SVG 内 CSS
<script>SVG 内 JS

g(グループ)

<g fill="orange" stroke="black" transform="translate(50, 0)">
  <circle cx="0" cy="50" r="20" />
  <circle cx="40" cy="50" r="20" />
</g>

defs / use / symbol

部品を 1 度定義して何度も再利用:

<svg viewBox="0 0 200 100">
  <defs>
    <symbol id="star" viewBox="0 0 10 10">
      <polygon points="5,0 6,4 10,4 7,6 8,10 5,8 2,10 3,6 0,4 4,4" />
    </symbol>
  </defs>

  <use href="#star" x="0"   y="0"  width="20" height="20" fill="gold"/>
  <use href="#star" x="40"  y="0"  width="20" height="20" fill="silver"/>
  <use href="#star" x="80"  y="0"  width="20" height="20" fill="bronze"/>
</svg>

外部 SVG の参照

<use href="/sprites.svg#icon-home" />

スプライトシートに集約してアイコンを共有する古典的手法。

title と desc(アクセシビリティ)

<svg role="img" aria-labelledby="title desc">
  <title id="title">Bar chart</title>
  <desc id="desc">Sales data for Q1〜Q4 2026</desc>
  ...
</svg>

装飾的なら

<svg aria-hidden="true" focusable="false">...</svg>

HTML 文書中の埋め込み方法

1. インライン(最も柔軟)

<svg viewBox="0 0 24 24" width="24" height="24">
  <path d="..." />
</svg>

2. img 要素

<img src="logo.svg" alt="Logo" width="200" height="80" />

外部スクリプト / 内部 JS / CSS 外部参照は動かない。CSS で色を変えられない。

3. background-image

.bg {
  background-image: url('pattern.svg');
}

4. object / iframe(古典)

スクリプトは動くがほぼ使わない。

JS から色を変える

インライン SVG なら通常の DOM 操作。

document.querySelector("#icon path").setAttribute("fill", "red")
document.querySelector("#icon path").style.fill = "red"

currentColor

CSS の color を継承。テーマ色とアイコンを連動させる定番技:

<svg fill="currentColor">...</svg>

<style>
  button { color: white; }
  button:hover { color: orange; }
</style>

SVG 内のスタイリング

優先順位

インライン style > 外部/内部 CSS > 属性 fill="..."
      

CSS で動的に変えたいなら属性で初期値、CSS で上書きが定石。

サイズ指定の落とし穴

「width / height があるとレスポンシブにならない」

<!-- 幅 100% に -- >
<svg viewBox="0 0 200 100" style="width: 100%; height: auto">...</svg>

<!-- または -->
<svg viewBox="0 0 200 100" width="100%" height="100%">...</svg>

「width / height 省略時はデフォルト 300x150」

viewBox があっても、CSS で大きさが決まらないと 300×150 で表示される。

名前空間

<svg xmlns="http://www.w3.org/2000/svg">
  ...
</svg>

SVG の構造例(アイコン)

<svg
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 24 24"
  fill="none"
  stroke="currentColor"
  stroke-width="2"
  stroke-linecap="round"
  stroke-linejoin="round"
  width="24"
  height="24"
  aria-hidden="true"
>
  <path d="M3 12h18M3 6h18M3 18h18" />
</svg>

スプライトシート(アイコン管理)

<!-- icons.svg -->
<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <symbol id="home" viewBox="0 0 24 24">...</symbol>
    <symbol id="user" viewBox="0 0 24 24">...</symbol>
  </defs>
</svg>

<!-- 使う側 -->
<svg width="24" height="24">
  <use href="/icons.svg#home" />
</svg>

react / vue で使う

import IconHome from "./home.svg?react"

function Header() {
  return <IconHome className="size-6 text-blue-500" />
}

失敗パターン

症状対処
サイズが 300x150 になるwidth / height 指定 or CSS で
img の SVG が CSS で色変えできないインライン or use にする
はみ出すviewBox / overflow="visible"
外部 SVG で xlink:href エラーhref に変更(現代)
外部 SVG にスクリプトが効かない仕様。インライン化
最初に身につける感覚

viewBox = 内部の座標系、width/height = 表示サイズ」。 この 2 つを別物として捉えると、レスポンシブも拡大も自由自在になる。