Claude CodeでSVG操作を安全に実装する実践ガイド
Claude CodeでSVG操作を始める人向けに、viewBox、アクセシビリティ、テーマ対応、アニメーション、SVGO最適化まで解説。
Claude CodeでSVGを扱う前に決めること
SVGは、アイコン、ロゴ、図解、簡単なチャートをHTMLの中で扱えるベクター画像形式です。拡大してもぼやけにくく、CSSで色を変えられ、Reactコンポーネントにも落とし込みやすいので、Claude Codeとの相性はかなり良いです。
ただし「SVGを書いて」と頼むだけだと、viewBoxがない、色がハードコードされる、スクリーンリーダーに不要なアイコン名が読まれる、アップロードSVGをそのまま差し込んでしまう、という失敗が起きます。Masaがこのサイトのアイコン検証で最初に詰まったのも、見た目ではなく「同じアイコンをボタン、見出し、ダークモードで再利用したときに壊れる」点でした。
この記事では、初心者がClaude Codeに任せても破綻しにくいSVG操作の型を作ります。インラインSVG、viewBox、アクセシブルなアイコン、currentColorとCSS変数によるテーマ対応、軽いアニメーション、SVGO最適化、レイアウトとセキュリティの落とし穴まで、コピーして動かせる例で整理します。
公式仕様の確認先は、MDNの<svg>要素、MDNのviewBox、MDNのARIA imgロール、MDNのaria-hidden、SVGO公式ドキュメント、Claude Code公式概要です。
全体像
SVG操作は「絵を作る作業」だけではありません。実務では、デザイン、HTML、CSS、アクセシビリティ、ビルド時最適化、レビューまでを一つの流れにします。
flowchart LR
A["目的を決める"] --> B["viewBoxと座標を固定"]
B --> C["currentColorでテーマ対応"]
C --> D["aria-labelまたはaria-hiddenを選ぶ"]
D --> E["React/HTMLへ組み込む"]
E --> F["SVGOで最適化"]
F --> G["表示・操作・安全性をレビュー"]
Claude Codeに依頼するときも、この順番を明示すると品質が安定します。たとえば「SVGアイコンを作って」ではなく、「viewBox="0 0 24 24"、stroke="currentColor"、装飾アイコンはaria-hidden、意味のあるアイコンはrole="img"とtitle、SVGOでviewBoxを消さない設定まで作って」と頼みます。
インラインSVGとviewBoxの基本
インラインSVGとは、画像ファイルをimgで読み込むのではなく、HTMLやJSXの中に<svg>を直接書く方法です。CSSで塗りや線を変えたいアイコン、状態に応じて表示を変えるUI部品、軽いアニメーションには向いています。
viewBoxは、SVG内部の仮想キャンバスです。MDNではmin-x min-y width heightの4つの数値でSVG viewportの位置と寸法を定義すると説明されています。初心者向けに言い換えると、「この絵は0から24までの方眼紙で描く」と決める設定です。
<button class="icon-button" type="button" aria-label="検索する">
<svg
class="icon"
viewBox="0 0 24 24"
width="24"
height="24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
focusable="false"
>
<circle cx="11" cy="11" r="7" />
<path d="M20 20l-4.5-4.5" />
</svg>
</button>
この例では、ボタン自体にaria-label="検索する"があるため、SVGは装飾扱いでaria-hidden="true"にしています。アイコンだけをスクリーンリーダーへ読ませるのではなく、操作対象であるボタンに名前を付けるのが安全です。
widthとheightは表示サイズ、viewBoxは絵の座標です。width="48"にしてもviewBox="0 0 24 24"のままなら、24単位で描いた絵が48pxへ拡大されます。反対にviewBoxを消すと、レスポンシブ表示で欠けたり、SVGO後にスケールできなくなったりします。
currentColorとCSS変数でテーマ対応する
currentColorは、現在のCSSのcolor値をfillやstrokeへ渡すための値です。SVGアイコンに直接#333333や#0ea5e9を書くと、テーマ変更、ホバー、ダークモード、ブランド色変更のたびにSVG本体を直すことになります。
色はCSS側へ寄せ、SVGはcurrentColorを受けるだけにすると、Claude Codeで一括修正しやすくなります。
:root {
--color-text: #172033;
--color-muted: #667085;
--color-accent: #0f766e;
--color-danger: #b42318;
}
[data-theme="dark"] {
--color-text: #eef2f7;
--color-muted: #a9b4c3;
--color-accent: #2dd4bf;
--color-danger: #f97066;
}
.icon {
color: var(--icon-color, var(--color-text));
display: inline-block;
inline-size: 1.25rem;
block-size: 1.25rem;
flex: 0 0 auto;
}
.icon-button {
color: var(--color-muted);
}
.icon-button:hover {
color: var(--color-accent);
}
.icon-button[data-variant="danger"] {
--icon-color: var(--color-danger);
}
<button class="icon-button" type="button" aria-label="削除" data-variant="danger">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" aria-hidden="true">
<path d="M4 7h16" />
<path d="M10 11v6" />
<path d="M14 11v6" />
<path d="M6 7l1 14h10l1-14" />
<path d="M9 7V4h6v3" />
</svg>
</button>
Claude Codeにテーマ対応を頼むときは、「SVG内のfillとstrokeに固定色が残っていないか検索して」と明示します。rg "fill=\"#|stroke=\"#"のような確認コマンドも一緒に依頼すると、レビューが具体的になります。
Reactでアクセシブルなアイコンを作る
意味のあるSVGは、スクリーンリーダーへ単一の画像として名前を渡します。MDNは、埋め込みSVGにrole="img"を付け、ラベルを与える方法を紹介しています。一方、テキスト付きボタンの横にある装飾アイコンなら、aria-hidden="true"でアクセシビリティツリーから外します。
Reactでは、titleがあるときだけ読み上げ対象にし、装飾アイコンは隠すコンポーネントにしておくと、使う側が迷いにくくなります。
import { useId } from "react";
type IconName = "search" | "check" | "close";
const paths: Record<IconName, string> = {
search: "M10.5 18a7.5 7.5 0 1 1 5.3-12.8 7.5 7.5 0 0 1-5.3 12.8Zm5.3-2.2L21 21",
check: "M5 12.5l4.5 4.5L19 7",
close: "M6 6l12 12M18 6L6 18",
};
type SvgIconProps = {
name: IconName;
title?: string;
decorative?: boolean;
size?: number;
className?: string;
};
export function SvgIcon({
name,
title,
decorative = false,
size = 24,
className,
}: SvgIconProps) {
const titleId = useId();
const isMeaningful = !decorative && Boolean(title);
return (
<svg
className={className}
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
role={isMeaningful ? "img" : undefined}
aria-labelledby={isMeaningful ? titleId : undefined}
aria-hidden={decorative ? true : undefined}
focusable="false"
>
{isMeaningful ? <title id={titleId}>{title}</title> : null}
<path d={paths[name]} />
</svg>
);
}
使い方は次のように分けます。
<button type="button">
<SvgIcon name="check" decorative />
保存する
</button>
<SvgIcon name="search" title="検索" />
1つ目はボタン内テキストが操作名なのでアイコンは装飾です。2つ目はアイコン自体が意味を持つため、titleを渡します。aria-hidden="true"をフォーカス可能な要素や重要なリンクへ付けるのは避けてください。MDNも、aria-hidden="true"をフォーカス可能な要素へ使わないよう注意しています。
軽いアニメーションを入れる
SVGアニメーションは、ローディング、成功チェック、チャートの強調などに使えます。ただし、記事や管理画面では派手さよりも「本文の邪魔をしない」「prefers-reduced-motionを尊重する」「レイアウトを揺らさない」が優先です。
以下はCSSだけで動くローディングアイコンです。SVGのサイズは固定し、CSSで回転だけを制御します。
<svg class="spinner" viewBox="0 0 48 48" width="48" height="48" role="img" aria-label="読み込み中">
<circle class="spinner-track" cx="24" cy="24" r="20" />
<circle class="spinner-head" cx="24" cy="24" r="20" />
</svg>
.spinner {
color: #0f766e;
animation: spin 900ms linear infinite;
}
.spinner-track,
.spinner-head {
fill: none;
stroke-width: 4;
}
.spinner-track {
stroke: #d0d5dd;
}
.spinner-head {
stroke: currentColor;
stroke-linecap: round;
stroke-dasharray: 80 45;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.spinner {
animation: none;
}
}
記事内の関連技術として、CSS側の表現を深掘りするならClaude Code CSSアニメーション高度テクニックもつながります。SVGはベクターの形、CSSは状態と動き、と役割を分けると保守しやすくなります。
データをSVGで描く最小例
SVGは簡単なチャートにも使えます。外部ライブラリを入れるほどではない小さな棒グラフなら、TypeScriptでSVG文字列を生成できます。ただし、ユーザー入力を<text>へ入れる場合はXMLエスケープが必要です。
type BarDatum = {
label: string;
value: number;
};
function escapeXml(value: string): string {
return value.replace(/[<>&"']/g, (char) => {
const entities: Record<string, string> = {
"<": "<",
">": ">",
"&": "&",
'"': """,
"'": "'",
};
return entities[char];
});
}
export function createMiniBarChart(data: BarDatum[]): string {
const width = 420;
const height = 180;
const padding = 32;
const gap = 12;
const maxValue = Math.max(...data.map((item) => item.value), 1);
const barWidth = (width - padding * 2 - gap * (data.length - 1)) / data.length;
const bars = data
.map((item, index) => {
const barHeight = (item.value / maxValue) * 100;
const x = padding + index * (barWidth + gap);
const y = height - padding - barHeight;
return `
<rect x="${x}" y="${y}" width="${barWidth}" height="${barHeight}" rx="6" fill="currentColor" />
<text x="${x + barWidth / 2}" y="${height - 10}" text-anchor="middle" font-size="12">
${escapeXml(item.label)}
</text>`;
})
.join("");
return `<svg viewBox="0 0 ${width} ${height}" role="img" aria-label="月別の問い合わせ数" xmlns="http://www.w3.org/2000/svg">
<g color="#0f766e">${bars}</g>
</svg>`;
}
このサンプルは、社内ダッシュボード、記事内の小さな比較図、LPの実績表示に使えます。大量データや軸、凡例、ツールチップが必要な場合は、専用チャートライブラリを使う判断も必要です。
SVGOで最適化する
FigmaやIllustratorから出したSVGには、エディタ由来の属性、不要なメタデータ、余分な小数が残りがちです。SVGOはSVG最適化ツールで、公式ドキュメントではCLI、Node.jsライブラリ、ブラウザ、Webpack loaderがサポートされると説明されています。
最初はviewBoxを守る設定にして、差分を目で確認しながら使うのが安全です。SVGOのremoveDimensionsは最上位svgのwidthとheightを削り、必要ならviewBoxへ置き換えるプラグインです。一方、removeViewBoxはスケールできなくなる危険があるため、レスポンシブなアイコンでは基本的に避けます。
// svgo.config.mjs
export default {
multipass: true,
plugins: [
{
name: "preset-default",
params: {
overrides: {
cleanupIds: false
}
}
},
"removeDimensions",
{
name: "removeAttrs",
params: {
attrs: ["data-name"]
}
}
]
};
{
"scripts": {
"svg:optimize": "svgo --config svgo.config.mjs --folder src/assets/icons"
},
"devDependencies": {
"svgo": "^4.0.0"
}
}
Claude Codeには、単に設定を作らせるだけでなく、次のようにレビュー込みで依頼します。
src/assets/icons配下のSVGをSVGOで最適化したいです。
viewBoxは絶対に残してください。
currentColorでテーマ変更できるか確認してください。
before/afterのファイルサイズ、消えた属性、見た目に影響しそうな差分を表で報告してください。
ユースケースを3つ以上で考える
1つ目は、記事サイトやSaaS管理画面のアイコンシステムです。検索、閉じる、保存、警告、外部リンクのような小さなアイコンは、viewBox="0 0 24 24"、currentColor、Reactコンポーネントで統一すると、色とサイズをUI側から制御できます。
2つ目は、技術記事の概念図です。コードだけだと読者が離脱する場面で、SVGの箱、矢印、ラベルを使うと理解しやすくなります。Claude Codeに「この説明をSVG図解にして」と頼むときは、テキスト量を少なくし、スマホ幅でも読めるサイズにする条件を付けます。
3つ目は、LPや教材販売ページの収益導線です。料金表、チェックリスト、購入ボタンの近くに軽いSVG図解を置くと、単なる装飾ではなく「購入前の不安を減らす情報」になります。ClaudeCodeLabの教材・テンプレート一覧やClaude Code導入相談へつなぐページでも、CTAを邪魔しない図解が重要です。
4つ目は、管理画面の小さなデータ表示です。問い合わせ件数、読了率、CTAクリック率のような小さな比較なら、SVGで十分なことがあります。複雑なグラフにする前に、最小のSVGで読めるかを試すと実装が軽くなります。
| 使い方 | 向いているSVG形式 | 注意点 |
|---|---|---|
| アイコン | インラインSVG、Reactコンポーネント | 装飾か意味ありかを分ける |
| ロゴ | imgまたはインラインSVG | ブランド色と代替テキストを確認する |
| 図解 | インラインSVG | スマホで文字が潰れないようにする |
| 小さなチャート | 生成SVG | ユーザー入力をエスケープする |
失敗例とセキュリティの落とし穴
SVGはHTMLに近い表現力を持ちます。MDNにはSVGの<script>要素があり、SVG文書にスクリプトを追加できることが説明されています。つまり、ユーザーがアップロードしたSVGを無条件でインライン挿入するのは危険です。
| 失敗例 | 何が起きるか | 対策 |
|---|---|---|
viewBoxを消す | レスポンシブで欠ける、拡大縮小できない | SVGO設定とレビューで残す |
fill="#000"が残る | ダークモードやホバーで色が変わらない | currentColorへ寄せる |
意味のあるアイコンにaria-hidden | 支援技術へ操作の意味が伝わらない | ボタンやSVGへ適切な名前を付ける |
| 装飾アイコンを読み上げる | 「検索 アイコン 検索」など重複する | 装飾はaria-hidden="true" |
| アップロードSVGを直接挿入 | スクリプトやイベント属性のリスク | 信頼できるSVGだけインライン化する |
| アニメーションを止められない | 動きに弱い読者へ負担が出る | prefers-reduced-motionを使う |
idが衝突する | グラデーションやマスクが別アイコンへ影響する | useIdやSVGO設定を確認する |
Claude Code側の安全性もセットで考えます。Claude Code公式セキュリティページでは、読み取り専用権限や追加操作時の許可について説明されています。SVG最適化のようにファイルを一括変更する作業では、最初に対象ディレクトリを限定し、git diff --checkと差分レビューを必ず挟みます。
Claude Codeに渡すプロンプト例
そのまま使える依頼文は次です。アイコンを作るだけでなく、レビュー観点まで含めています。
このリポジトリの既存デザインに合わせて、SVGアイコンコンポーネントを追加してください。
条件:
- viewBoxは0 0 24 24で統一
- fillまたはstrokeはcurrentColorを使う
- テキスト付きボタン内の装飾アイコンはaria-hidden=true
- アイコン単体で意味がある場合はrole=imgとtitleを使う
- prefers-reduced-motionを尊重した簡単なローディングSVGも追加
- SVGO設定を作る。ただしviewBoxは削除しない
- 最後に失敗例、セキュリティ注意点、確認コマンドを報告
実装後に見るべきチェックリストは短くて十分です。
viewBoxが残っている- 固定色が必要なロゴ以外で
currentColorが使われている - ボタン、リンク、アイコン単体のアクセシブル名が重複していない
- 375px幅で図解の文字が読める
- SVGO後も見た目が変わっていない
- ユーザー投稿SVGをインライン挿入していない
- 変更範囲がアイコン、CSS、設定に限定されている
まとめと収益導線
Claude CodeでSVG操作を任せるときは、見た目の生成よりも、再利用できるルール作りが重要です。viewBoxで座標を固定し、currentColorとCSS変数でテーマ対応し、ARIAで装飾と意味を分け、SVGOで余分な情報を落とす。この順番にすると、アイコン、図解、チャート、LPのCTA周りまで同じ設計で扱えます。
表示速度への影響も見るならClaude Codeパフォーマンス最適化、動きの設計を広げるならCSSアニメーション高度テクニックも合わせて確認してください。
自分のプロジェクトでSVG、アイコン設計、CLAUDE.md、レビュー観点まで整えたい場合は、ClaudeCodeLabの教材・テンプレート一覧で土台を作るか、チーム導入ならClaude Code導入相談・研修で実リポジトリ前提の設計を相談できます。
この記事で紹介した内容を実際に試した結果
Masaの検証用UIでは、SVG内の固定色をcurrentColorへ寄せ、viewBoxを残すSVGO設定にしただけで、ライトテーマ、ダークテーマ、警告ボタンの3パターンを同じアイコンで使い回せました。一方で、最初にaria-hiddenを機械的に付けたアイコンは、アイコンだけの検索ボタンで名前が消えました。SVGは小さな部品ですが、Claude Codeに「見た目、アクセシビリティ、最適化、安全性」を同時にレビューさせると、公開前の手戻りがかなり減ります。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Code権限セーフティラダー: 初心者がallowを広げる順番
Claude Codeの権限をread-onlyからbuild、限定編集、deploy確認まで段階的に広げる安全な運用手順。
Claude Code Small PR Proof Pack: 小さなPRをレビュー可能にする証拠セット
Claude Codeの小さなPRに、差分・検証・公開URL・CTA・rollbackを添える実務チェックリスト。
Claude Codeのコミット前レビューゲート: 差分、テスト、CTAをまとめて止める型
Claude Codeでcommit前に差分をレビューする実践手順。build、公開URL、CTA、Gumroadリンク、未翻訳本文を検知します。