構造と座標系
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>
- xmlns — 名前空間(インライン SVG では省略可、外部ファイルは必須)
- width / height — 表示サイズ(CSS で上書き可)
- viewBox — 内部座標系
- preserveAspectRatio — viewBox とサイズの比率不一致時の挙動
2 つの座標系
- 外側: width / height(CSS px)
- 内側: viewBox(独自単位)
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 は下に増える(数学とは逆)
- 単位はそのまま数値(px は付けない)
(0,0) ─────→ x
│
│
│
▼
y
preserveAspectRatio
viewBox の比率と width/height の比率がズレた時の挙動を決める。
preserveAspectRatio="xMidYMid meet"
└────────┘ └──┘
アライン フィット方式
アライン
| 値 | 意味 |
|---|---|
| none | 比率を無視して引き伸ばす |
| xMinYMin | 左上に寄せる |
| xMidYMid | 中央に寄せる(既定) |
| xMaxYMax | 右下に寄せる |
| xMinYMid 等の組合せ | X / Y を別々に |
フィット方式
- meet(既定)— 全体が収まるように縮小(余白あり)。CSS の
contain - slice — はみ出す部分は切る。CSS の
cover
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 内のスタイリング
- 属性で指定:
fill="red" - style 属性:
style="fill: red" - 外部 / 内部 CSS:
.icon { fill: red }
優先順位
インライン 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>
- HTML に直接書く場合は不要(HTML パーサが SVG を判別する)
- 外部 .svg ファイルは必須
- 古い
xlink:hrefは不要(モダンならhref
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 で使う
- SVG をそのままコンポーネントに
- Vite / Next.js なら
vite-plugin-svgr/@svgr/webpack - あるいは
?rawimport で文字列に - アイコンは Lucide / Heroicons / Tabler の React 版が便利
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 つを別物として捉えると、レスポンシブも拡大も自由自在になる。