SVGの基本

目次
  1. SVGについて
  2. viewBoxとwidth属性・height属性
  3. 基本的な図形
  4. 色をつける
    1. fillとstroke
    2. グラデーション
    3. パターン
  5. テキスト入力
  6. トランスフォーム属性
  7. クリッピングとマスキング
  8. imags要素

SVGについて

SVGは、ベクター形式(データを数値で管理)の画像フォーマット(パソコンで画像を取り扱うための規則)の1つです(拡張子は「.svg」)
SVGはXMLという「マークアップ言語(タグで囲んで構造を表現し、意味付けする言語)」なので、テキストエディタで描画や編集ができ、HTMLファイルに埋め込むことができます
*(注意)XMLはHTMLとは異なり大文字と小文字を区別します

SVGの特徴

  • 拡大してもギザギザがあらわれることなく画像が劣化しない
  • 解像度を気にすることなく、複数の画像を用意する必要がない
  • アニメーションが可能
  • 画像ファイルとして読み込む以外に、HTMLに埋め込んで記述できる

*写真のような画像には不向きで平面座標系のため3Dの描画はできない

SVGファイル(.svg)を、画像ファイルとして読み込む

 <!-- img要素のsrc属性に -->
<img src="../images/hoge.svg" width="50" height="50" alt=""> 
 <!-- ファビコンに -->
<link rel="icon" href="images/favicon.svg" type="image/svg+xml">

svg要素として、HTMLに埋め込む(インラインSVG)
svg要素はHTMLのDOM ツリーとして、CSS やJavaScriptで操作できます
*svg要素はインライン要素です

 <svg xmlns="http://www.w3.org/2000/svg" width="" height="" viewBox="x y width height">
  <!-- ここにSVGの要素を記述 -->
</svg>

インラインSVGはアニメーションができて便利なのですが、SVGタグが多くてHTMLファイルが複雑になってしまいます。
そこでJavaScriptで動的に挿入すると便利です
*SVGファイルとHTMLファイルが同一オリジン(同じドメイン)でないと、クロスオリジン制限によってfetchが失敗する可能性があります

<div id="svg-container"></div>
fetch('path/image.svg')
  .then(response => response.text())
  .then(data => {
    const container = document.getElementById('svg-container');
    container.innerHTML = data;
  });

//複数のSVGファイルを並行して読み込む
Promise.all([
    fetch('/path/to/svg1.svg').then(res => res.text()),
    fetch('/path/to/svg2.svg').then(res => res.text()),
    // ...
]).then(([svg1, svg2, /* ... */]) => {
    document.getElementById('svg-container1').innerHTML = svg1;
    document.getElementById('svg-container2').innerHTML = svg2;
    // ...
});

svg要素のおもな属性

xmlns
「xmlns=”http://www.w3.org/2000/svg”」は、URI のように見えますが「名前空間名」です
名前空間は、SVGとHTMLで同じタグや属性があるので、SVGとHTMLを区別するためのものです
(省略可)
xmlns:xlink
「xmlns:xlink=”http://www.w3.org/1999/xlink”」も「名前空間名」です
href属性(a要素やuse要素などで利用)を使うときに必要(省略可)
version
SVG のバージョンを指定(省略可)
*SVG2では非推奨
width
svg要素を表示する幅(ビューポートの幅)
*CSSで指定する場合は不要
数値のみの場合はpxとみなされます
height
svg要素を表示する高さ(ビューポートの高さ)
*CSSで指定する場合は不要
数値のみの場合はpxとみなされます
viewBox
ビューポートとは別の座標系を指定します
viewBox="x y width height"
X座標の最小値・ Y座標の最小値・ X軸の幅・ Y軸の高さ
*pxやcmなどの絶対単位はsvg要素のwidthとheight 属性で指定します

<svg>要素は入れ子にできます(<svg>の中に<svg>OKです)

viewBoxとwidth属性・height属性

「ビューポート」はwidthとheight属性で決まります

「ビューポート」と「viewBox」は異なる「単位」と「座標軸」があります

  • 「viewBox」はユーザから見えている範囲
  • 「ビューポート」はSVG要素の表示領域
    ポイント:ビューポートは見えている部分ではありません
    *widthとheight属性で決まるSVG要素の表示領域です
  • 「viewBox」がない場合
    デフォルトでは「viewBox」のサイズは「ビューポート」のサイズと同じです
  • widthとheightを指定せず(または100%)「viewBox」を指定したときはSVG要素は可変します
  • 「widthとheight」と「viewBox」両方ある場合は数値を変更して見え方を調整できます

単位について
「widthとheight属性の単位」はpxなどの絶対単位(%も可能)
「viewBoxの単位」は「ビューポート」の大きさで決まる、数字のみで指定する「ユーザ単位」です

「widthとheight属性の値(px)」「viewBoxのwidthとheight」1ユーザ単位
1000と1000500と5002px=1ユーザ単位
大きく表示されます
1000と10001000と10001px=1ユーザ単位
大きさに変化なし
500と5001000と10000.5px=1ユーザ単位
小さく表示されます

座標軸は、「ビューポート」「viewBox」ともに画面の左上を原点(0,0)です

SVGを扱う時は大体widthとheightは消してあとはCSS
*SVG要素のレスポンシブは簡単
あれ〜てなった時に忘れていることはだいたい次の2点です

  • SVGはインライン要素
  • 親要素のボックスをアスペクト比固定でレスポンシブにする場合は、通常「親のボックスのpadding-top: 縦幅/横幅*100%」に絶定位置で配置する

「widthとheight」と「viewBox」両方ある場合について

viewBoxのwidthとheightビューポート:ズームアウト
viewBoxのwidthとheightビューポート:ズームイン
「viewBox=”x y width height”」の「x 」と「y」を0以外で指定すると原点が移動します
グレー色の「viewBox」で実際の見え方です
黄色の枠は「ビューポート」

viewBoxのイメージ

ややこしいのは、「ビューポート」と「viewBox」でアスペクト比が異なるときです

「preserveAspectRatio」属性ではみ出した部分をどうするかなどを指定できます
デフォルトで「preserveAspectRatio=”xMidYMid meet”」が設定されています
かなりややこしい〜!!
既存のSVG画像を利用するときは理屈考えずにいじってみる💦

  • 「meet」はアスペクト比を保持してオブジェクトの長いほうを領域に合わせる
  • 「xMidYMid」は中央でそろえるようにして「ビューポート」内に「viewBox内の要素」をおさめます
  • 「preserveAspectRatio=”none”」を指定するとアスペクト比が崩れます

基本的な図形

実際の図形はドローツールで描いて、エクスポートして使うのが簡単です😅
XMLの構造だけわかればOK

rect
長方形を描画
<rect x="" y="" rx="" ry="" width="" height=""/>
x:X座標(左上の位置)
y : Y座標(左上の位置)
width : 長方形の幅
height : 長方形の高さ
rx : 長方形の角の、X 軸方向の半径(角を丸くするとき)
ry : 長方形の角の、Y 軸方向の半径(角を丸くするとき)
circle
円を描画
<circle cx="" cy="" r=""/>
r : 円の半径
cx : X座標(円の中心の位置)
cy : Y座標(円の中心の位置)
ellipse
楕円を描画
<ellipse cx="" cy="" rx="" ry=""/>
rx : 楕の半径 (X軸方向)
ry : 楕の半径 (Y軸方向)
cx : X座標(楕円の中心の位置)
cy : Y座標(楕円の中心の位置)
line
直線を描画 (始点と終点を結びます)
<line x1="" x2="" y1="" y2=""/>
x1 : X座標(始点の位置)
y1 : Y座標(始点の位置)
x2 : X座標(終点の位置)
y2 : Y座標(終点の位置)
polyline
連結された直線のグループ
<polyline points="0 0, 10 20,........"/>
points : X座標とY座標の間は数値は空白、次のX座標とY座標をカンマで区切ります
polygon
多角形(終端で線が最初の点とつながり閉じます)
<polygon points="0 0, 10 20,…….."/>
points : X座標とY座標の間は数値は空白、次のX座標とY座標をカンマで区切ります
path
複雑な形状の描画が可能です
d属性は、値にコマンドをとり要素の形状を定義します
例 <path d="m 10 10 h 90 v 90 h 10 Z"/>
*コマンドの大文字はページ上の絶対座標を指定し、小文字は相対座標を指定します
m:2つの点
l:直線を描画
h : 水平線
v : 垂直線
z : パスを閉じる
cとs : 三次ベジェ曲線
qとt: 二次ベジェ曲線
a : 円弧

図形の組み合わせや簡単な曲線は、Google図形描画が簡単です
もちろんエクスポートできます(Googleアカウントが必要ですが、Figmaなどの高機能なツールを使うほどでもないときは重宝します😊 )
*必要なパスは、ほぼ最終行です

色をつける

fillとstroke

fillとstroke属性

「fillは塗りつぶしの色」 「strokeは枠線の色」を設定します
*値は「色名・16進数値・RGB値 ・RGBA 値」など、CSSと同じです
*「fill-opacity属性」 「stroke-opacity属性」で透明度を指定できます

stroke="" fill="" fill-opacity="" stroke-opacity=""

ストロークを描画するときの属性

stroke-width
ストロークの幅
stroke-linecap
開いている線の端の形状
butt : パスの長さと同じ
square : パスよりも少しだけ長め
round : 先を丸める
stroke-linejoin
2本のの接続箇所
miter : とがった角(1本の角度だけを使用して四角い角を作成)
round : 丸みを帯びた角
bevel : とがった角の先を垂直に切った新しい角
stroke-dasharray
線の間隔を指定します
値が1つののときは、等間隔の破線です
値が複数のときは、カンマで区切ります
数字が2つは「最初の数字は塗りつぶされた部分の長さを」「 2 番目の数字は塗りつぶされていない部分の長さ」です
数字が3つの場合は2回ループで偶数のパターンを作り、このパターンが繰り返されます
stroke-dashoffset
線の開始位置を変更することができます

「stroke-linecap(左)」は「線の端」「stroke-linejoin(右)」は「角」をどのようにするかを指定します

stroke-linecap
stroke-linejoin

CSSの使用について

CSSのプロパティとしも使えるSVG属性がたくさんあり、例えば「fill, stroke, stroke-dasharray」もCSSのプロパティとして使えます

SVGの要素にstyle属性を用いるて直接書けます
style="stroke: black; fill: red;"

SVGの要素に:hover などの擬似クラスをあてるときは「class属性」をつけて対応します

defs要素
再利用するオブジェクトを定義するためのもので、要素内にオブジェクトは直接レンダリングされません
*レンダリングにはuse要素をつかいます
defs要素を使いインラインでCSSを書けます

<defs>
    <style type="text/css">
            .MyRect {
                stroke: black;
                fill: red;
            }
            .MyRect:hover {
             stroke: black;
                fill: blue;
            }
        </style>
  </defs>
  <rect x="10" height="180" y="10" width="180" class="MyRect"/>

グラデーション

グラデーションには、「線形グラデーション(linearGradient)」と「放射状グラデーション(radialGradient)」の 2 種類があります

  • グラデーションは「defs」内に定義します(再利用できます)
    id属性で名前をつけます」
  • グラデーション要素の内部には複数<stop>の要素を作成します
  • グラデーションを適用する図形はfill="url(#id名)"でグラデーションを利用します
 <svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <linearGradient id="Gradient" x1="1" x2="0" y1="0" y2="0">
            <stop offset="0%" stop-color="red" />
            <stop offset="50%" stop-color="black" stop-opacity="0" />
            <stop offset="100%" stop-color="blue" />
        </linearGradient>
        <radialGradient id="Gradient2" cx="0.25" cy="0.25" r="0.25">
            <stop offset="0%" stop-color="red" />
            <stop offset="100%" stop-color="blue" />
        </radialGradient>
    </defs>
    <rect x="10" y="10" width="100" height="100" fill="url(#Gradient)" />
    <rect x="10" y="120" width="100" height="100" fill="url(#Gradient2)" />
</svg>
<linearGradient>要素
線形グラデーション
デフォルトは水平方向のグラデーションです
グラデーションの方向を変更するには、「 x1・ x2・ y1・ y2 」属性で指定された2つの点を使います
<linearGradient x1="0" x2="0" y1="0" y2="1">
<radialGradient>要素
放射状グラデーション
デフォルトは図形の中心から放射線状のグラデーションです
グラデーションの中心点や大きさは「cx と cy属性で中心点」「r属性で半径」を変更できます
<adialGradient cx="0.5" cy="0.25" r="0.25">
「spreadMethod属性」で 塗りつぶされていない場合にどうするかを指定できます
spreadMethod=”pad” : 100%のカラーが残りの部分を埋める
spreadMethod=”repeat” : 100%のカラーから0%方向にグラデーションを折りかえす
spreadMethod=”reflect” : 再度0%からグラデーションが始まる
<stop>要素
グラデーションで使用する色と位置を定義します
<stop offset="" stop-color="" stop-opacity=""/>
offset:位置(「0%から100%」または「0から1」)
stop-color : 色
stop-opacity : 不透明度

パターン

パターンを設定した要素の中で、同じ画像を繰り返し描画します(背景画像になります)

  • パターンも「defs」内に定義します(再利用できます)
    「 id属性で名前をつけます」
  • pattern要素に「width 」「 height 」属性で「グラフィック要素のサイズを定義し、開始点をずらしたい場合は「 x 」「 y 」属性を指定します
  • パターンを適用する図形はfill="url(#id名)"でパターンを指定します
<svg width="1000" height="1000" xmlns="http://www.w3.org/2000/svg" version="1.1">
    <defs>
        <radialGradient id="Gradient">
            <stop offset="0%" stop-color="blue" />
            <stop offset="100" stop-color="white" />
        </radialGradient>
 <!--パターン1-->
    <pattern id="Pattern" x="0" y="0" width=".25" height=".25">
        <circle cx="25" cy="25" r="20" fill="url(#Gradient)" />
    </pattern>
 <!--パターン2-->
    <pattern id="Pattern2" x="0" y="0" width="50" height="50" patternUnits="userSpaceOnUse">
        <circle cx="25" cy="25" r="20" fill="url(#Gradient)" />
    </pattern>
 <!--パターン3-->
    <pattern id="Pattern3" width=".25" height=".25" patternContentUnits="objectBoundingBox">
        <circle cx=".125" cy=".125" r=".1" fill="url(#Gradient)"/>
    </pattern>
    </defs>

    <rect fill="url(#Pattern)" stroke="black" x="0" y="0" width="200" height="400" />
    <rect fill="url(#Pattern2)" stroke="black" x="200" y="0" width="200" height="400" />
    <rect fill="url(#Pattern3)" stroke="black" x="400" y="0" width="200" height="400" />
</svg>
SVGのパターン比較

「height」と「width」の値についての注意点

上の例の「パターン1」は、「height」と「width」を「0.25 」に指定しています
patternUnits属性」はpatternの単位を指定する属性です
「patternUnits属性のデフォルトの値」は「patternUnits=”objectBoundingBox“」で「枠となるオブジェクト全体を1」として計算します(0.25なので、4回繰り返します)
しかし、オブジェクトのサイズが変わっても繰り返す回数は同じで、「pattern要素内の基本図形(ここではcircle)」のサイズは変わりません

パターン2」は、patternの単位をデフォルトの値から「patternUnits=“userSpaceOnUse“」に変更し「width=”50” height=”50″」とピクセルで指定しています
サイズが決まっており、枠の形状に関係なく繰り返します

パターン3」は、patternの属性には「patternContentUnits属性」もあり、この属性はpattern自身の単位ではなく、「pattern要素内の基本図形(ここではcircle)」の単位を決める属性です
「patternContentUnitsのデフォルト値」は「patternContentUnits=”userSpaceOnUse”」です(patternUnits属性とは逆w)
そこで、デフォルト値から「patternContentUnits=”objectBoundingBox”」に変更し「pattern要素内の基本図形(ここではcircle)」の単位を変更しました(1をもとにして計算)
「pattern要素内の基本図形(ここではcircle)」隙間をうめるために、縦長になりました

テキスト入力

text要素
SVG内にテキストを入れることができます
「xとy属性」でテキストの位置を指定します
「fillやstroke属性」の指定もできます
<text x="10" y="10">テキスト</text>
text-anchor="middle"で文字列の中央をxとyで指定された位置にあわせることができます
alignment-baseline="middle"で文字列の中心を親要素のベースラインに親の高さの半分を加えたものに揃えることができます

その他のおもな属性(CSSでも設定できます)
font-family・font-style・font-weight ・font-variant ・font-stretch ・font-size ・font-size-adjust ・kerning ・letter-spacing ・word-spacing ・text-decoration
tspan要素
text要素またはtspan要素の子要素にしかなれません
一部の文字列のスタイルを変えたいときなどに使います
<tspan>テキスト</tspan>
xとy: 絶対X座標と絶対Y座標を設定
dxとdy : 現在位置から移動させるオフセットの値
rotate : 文字が指定した値の分だけ回転
tref要素
すでに定義しているテキストを参照(コピー)
<tref xlink:href="#example"/>
textPath
パスに沿って文字を並べます
<path id="my_path" d=..../>
<text>
<textPath xlink:href="#my_path">テキスト</textPath>
</text>

トランスフォーム属性

g要素について

「g要素」は、グループ化するために用いられるコンテナです
「g要素」の「トランスフォーム」はすべての子要素に実行さます
「g要素」の「属性」はすべての子要素に継承されます
「g要素」でグループ化しておくと、後に「use要素」で参照できます

transformの値

translate(x,[y])
移動(X軸・Y軸に指定した距離を移動します)
yを省略したときはY軸は0です
scale(x [,y])
拡大縮小(比率で拡大・縮小します)
「1」が等倍です
yを省略したときはxと同じ値です(同じ比率)
rotate(角度 [,x, y])
回転(指定された角度を時計回り回転します)
[,x, y]は、回転の中心になる座標です
[,x, y]を省略したときは要素の左上「0 0」が中心になります
skskewX(角度)
横方向にひっぱった傾斜(X軸に対する傾斜角度)
角度
skewY()
上方向にひっぱった傾斜(Y軸に対する傾斜角度)
matrix(A1, A2, B1, B2, C1, C2)
3×3の複雑なトランスフォーム

トランスフォーム属性はスペース区切りで連結できます

<g fill="red" transform="translate(30,40) rotate(45) scale(2) skewX(30)">
    <rect x="0" y="0" width="10" height="10" />
    <rect x="20" y="0" width="10" height="10" />
</g>

クリッピングとマスキング

「クリッピング」は切り抜きです
「マスキング」は透明度を考慮できます
*マスクは切り抜くのではなく「不透明度」を移植するためのものです
マスクが黒なら透明・マスクが白なら不透明

クリッピングします
「切り抜きたい画像」は、描画している状態です

  • <clipPath>要素で、表示したい領域を設定します(領域の外側は描画されません)
  • <clipPath>要素に「id属性で名前をつけます」
  • 「切り抜きたい画像」の要素に「clip-path属性」で「clip-path="url(#id名)"」を指定します
<clipPath id="heart">
    <path d="M10,30 A20,20,0,0,1,50,30 A20,20,0,0,1,90,30 Q90,60,50,90 Q10,60,10,30 Z" />
</clipPath>
<image href="..." x="0" y="-100" height="300" width="200" clip-path="url(#heart)"/>

「グラデーション」と要素を使ってマスキングします
「フェードアウトしたい画像」は、描画している状態です

  • グラデーションを「基本的にはdefs」内に作り、「 id属性で名前をつけます」
  • グラデーション要素の内部には<stop>要素を作成します
  • <mask>要素で、マスクをかけたい領域を設定し「fill="url(#グラデーションのid名)“」でグラデーションを指定します
  • <mask>要素に、「 id属性で名前をつけます」
  • 「フェードアウトしたい画像」の要素に「mask属性」で「mask="url(#maskのid名)"」を指定します
<defs>
<linearGradient id="Gradient">
   <stop offset="0" stop-color="white" stop-opacity="0" />
   <stop offset="1" stop-color="white" stop-opacity="1" />
</linearGradient>
<mask id="Mask">
  <rect x="0" y="0" width="200" height="200" fill="url(#Gradient)" />
</mask>
</defs>
<image href="..." x="0" y="-100" height="300" width="300" mask="url(#Mask)"/>

imags要素

要素で、画像を表示します
height属性またはwidth属性が「ないか0」のときは画像は表示されません
x属性とy属性がないときは「0」 になります

<svg width="500" height="500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
<image href="hoge.png" x="0" y="0" height="500" width="500" />
</svg>

参考