KDE BLOG

バイブス

【SVG 基礎 vol.1】SVGとは・viewPortとviewBox・基本の書き方・埋め込み方法

これまでSVGに関しては、アイコンやロゴをpngやgifなどのビットマップ画像の代わりに少し使う程度で、アニメーションに関してもCSSアニメーションやJavaScriptのDOMアニメーションで事足りていました。
しかしSVGのことをちゃんと知ってマイクロインタラクションとして使えるようになりたいと思ったので基礎から勉強します。

SVGとは

SVG(Scalable Vector Graphics)は、XMLをベースとしたベクターグラフィックス用の画像フォーマットです。
XMLそのものなので、画像フォーマットであり、かつテキストファイルでもあります。
JPEGPNGなどのビットマップ画像とは全く異なる性質を持っています。

ベクターグラフィックスである

SVGは、Webで使える唯一の正式な仕様を持ったベクター形式の画像フォーマットです。
ベクター形式のため、拡大・縮小をしても画像が荒れることがないため、マルチデバイス向けのサイト制作において重宝できます。

XMLである

XMLであるため下記のメリットがあります。

  • 文書であるためテキストファイルとして編集が可能
  • テキストノード(純粋な文字情報)を含めることが可能
  • 画像内のパーツごとにCSSによる装飾が可能
  • JavaScriptでDOM操作が可能(動的に画像そのものを変更できる)
  • SVG内に外部リソースの参照(埋め込み)が可能
  • 画像内にアクセシビリティの担保が可能
  • コードであるため、Git管理が可能

SVGという名前の「Scalable」の通り「拡張性の高い」画像フォーマットです。

ブラウザ対応

Can I use... Support tables for HTML5, CSS3, etc
上記の通り、PCであればIE9以上、SPであればandroid3以上であれば基本的に使えます。

  • android4.4未満ではマスキングをサポートしていないようです
  • IE9〜 および Edge は、SVGファイルを適切にスケーリングしません。高さ、幅、viewBox、およびCSSルールを追加することが最善の回避策とのことです

宣言と名前空間

SVGは基本的に、XHTML文書と同様に

が必要となります。

<?xml version="1.0" standalone="no" encoding="UTF-8"?><!-- XML宣言 -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><!-- DOCTYPE宣言 -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" viewBox="0 0 200 200"><!-- 名前空間の宣言 -->
  ...
</svg>

XML宣言

このドキュメントがXML文書であることを示しています。

※文書の文字コードUTF-8もしくはUTF-16XMLのversionが1.0、スタンドアロン文書宣言が no という条件を満たしていれば省略可能です。
Illustratorやsketchから書き出したSVGもこの条件に当てはまるため、この宣言を省略できます。

DOCTYPE宣言

バージョンやタグのルールなどが示されていて、バリデーションのために記述します。
現在すでに使われているSVG 1.1 Second Editionでは省略可能です。

名前空間の宣言

<svg>SVGのルート要素で、HTMLにおける <html> に相当します。
このタグ内の xmlns 属性の値に、SVG名前空間 http://www.w3.org/2000/svg が宣言されることで <svg> 要素の配下でSVG固有のタグが利用できるようになります。
たとえば a 要素は通常の html にも svg にも存在しますが、このネームスペース配下に置くことで html と混ざることなく SVG の a 要素として使うことができます。
ちなみに、SVG名前空間で使われている http://www.w3.org/2000/svg はURLですが、ただの識別子の文字列です。 URLの参照先自体には意味はありません。
URLは1つの場所しか示さないので、ID(名字)として利用されているのが慣習のようです。
このネームスペースをタイプミスしてしまうとSVGではない別の言語として解釈されてしまうので注意が必要です。

xmlns:xlink は文書内で a 要素や use 要素などで href 属性を使う場合に必要な宣言です。
xmlns:ev はonclick属性などのイベント属性で必要な宣言です。

少なくとも xmlnsxmlns:xlink は宣言しておくと良いですが、HTML5でインラインSVG(後述)の場合は両方とも省略することが可能です。

viewPortとviewBox

svgには「viewPort」と「viewBox」という概念があります。
viewPortはSVGの世界を見るための窓で、窓の大きさはsvg要素の widthheight 属性で決まります。
viewBoxは、窓の中にSVGのどこからどこまでを収めるか を指定します。

viewBoxについて

viewBoxについてもっと詳しくいうと、viewBoxはSVGの内容を表示させる「表示領域」と図形の配置や大きさの基準となる「座標系」を定義します。
viewBoxの指定は下記のように、viewBox="X座標の最小値 Y座標の最小値 X軸の幅 Y軸の高さ" と記述します(単位は指定しません)。

<svg viewBox="0 0 200 200">

上記の場合「200px × 200px」の大きさを示しているわけではありません。
pxやcmなどの絶対単位は、先述の通りsvg要素の widthheight 属性で指定します。
この絶対単位に対して「座標系」における単位を利用単位といいます。
svg内のそれぞれの図形は、この利用単位で配置やサイズを指定するので、通常は絶対単位での指定はしません

viewPortとviewBoxの関係

viewPortの大きさはwidth、height属性で絶対単位での指定で決まります(別途CSSで指定・上書きが可能)。
SVGの座標系は特定の絶対単位を持たないため、1利用単位のサイズは、viewPortの大きさによって異なります

例えば <svg viewBox="0 0 100 100" width="100" height="100"> の場合は 1利用単位 = 1px となりますが、 <svg viewBox="0 0 100 100" width="200" height="200"> の場合は 1利用単位 = 2px となります。

下記が実際のデモです。

https://codepen.io/KDE_SPACE/pen/jvBBEdcodepen.io

円の大きさだけでなく、線の太さも変わっているのが確認できます。
このように座標系の利用単位が変化することを「座標系変換」といいます。

SVGにおける1座標(利用単位)は、width、heightをviewBoxで定義したX軸、Y軸のそれぞれの値で割ったサイズということになります。

通常は、1座標 = 1px として扱う方が余計な混乱をきたさないかと思います。

※ viewport と viewbox の関係は深いので、詳しくは別途まとめようと思っています。

主な SVG 要素

circle 要素

中心座標と半径を指定して円を描画します。

<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" viewBox="0 0 500 500">
  <circle cx="150" cy="200" r="100" fill="#e00" />
</svg>
専用属性 説明
cx 円の中心の x 座標(center x の意味)
cy 円の中心の y 座標(center y の意味)
r 円の半径の長さ(radius の意味)

※ 専用属性とはこの要素特有の属性のことを指す模様です。
この専用属性以外にも fill などのグラフィカルイベント属性と呼ばれる属性などを指定できます。詳しくは MDN などのリファレンスを参照ください。
circle - SVG: Scalable Vector Graphics | MDN

f:id:jinseirestart:20191209211611p:plain
表示結果

rect 要素

矩形を描画します。
矩形を描画する際の基準となる座標と、そこからの幅と高さを指定します。
また、角丸四角形も作成できます。

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" viewBox="0 0 300 300">
  <rect x="10" y="10" width="50" height="50" rx="10" fill="#c00" />
  <rect x="50" y="100" width="50" height="100" rx="10" ry="50" fill="#0a0" />
  <rect x="120" y="200" width="50" height="50" rx="50%" fill="#00d" />
</svg>
専用属性 説明
x 原則、要素の左上を原点とした x 座標
y 原則、要素の左上を原点とした y 座標
width 横幅
height 高さ
rx x軸の半径
ry y軸の半径

f:id:jinseirestart:20191209212722p:plain
表示結果

line 要素

2点の座標を繋いた直線を描画します。

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" viewBox="0 0 300 300">
  <line x1="0" y1="0" x2="300" y2="300" stroke="#e00" stroke-width="3" />
  <line x1="250" y1="30" x2="20" y2="200" stroke="#00e" stroke-width="10" stroke-dasharray="20 5" />
</svg>
専用属性 説明
x1 開始地点の x 座標
x2 開始地点の y 座標
y1 終了地点の x 座標
y2 終了地点の y 座標

f:id:jinseirestart:20191209214409p:plain
表示結果

その他にもたくさんの要素がありますが、それはまた別途調べたいと思います。

埋め込み方法

svg を実際にWebコンテンツとしてHTMLに埋め込む方法は下記になります。

1. img要素として埋め込む

SVGは画像でもあるので、img要素として簡単に埋め込むことができます。

▼ circle.svg

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">
    <circle cx="100" cy="100" r="50" fill="tomato" />
</svg>

▼ index.html

Hello, SVG. <img src="circle.svg" alt="">

f:id:jinseirestart:20191213005528p:plain
img要素での埋め込み表示結果

上記では img 要素に対して背景色グレーを指定します。SVG自体は円以外は透過です。
img要素にwidth、heightを指定して縮小しても拡大しても基本的に画像が荒れることはありません。

f:id:jinseirestart:20191213010003p:plain
<img src="circle.svg" alt="円" width="900" height="900"> にした結果

2. 背景画像として埋め込む

CSSで背景画像として使うこともできます。

▼ circle.svg(上記と同じ)

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">
    <circle cx="100" cy="100" r="50" fill="tomato" />
</svg>

▼ html

<div class="bg">Hello, SVG.</div>

css

.bg {
  width: 300px;
  height: 300px;
  background: #eee url('circle.svg') 0 0;
  background-size: 30px auto;
}

f:id:jinseirestart:20191213011124p:plain
背景画像での表示結果

3. 要素(インラインSVG)として埋め込む

タグとしてhtmlに埋め込んだ場合、xmlns属性を省略することが可能です。
svgタグにはwidthとheightを指定します。

<body>
  <svg width="300" height="300">
    <circle cx="100" cy="100" r="50" fill="tomato" />
  </svg>
</body>

f:id:jinseirestart:20191218005943p:plain
表示結果

※ ちなみに、width と height を指定しない場合、デフォルトで width="300" height="150" となります。

インラインSVGの場合、htmlと同じくDOMツリーが作成されます。
devTool で確認すると下記のようになります。

f:id:jinseirestart:20191218010421p:plain
インラインSVGではDOMツリーが作成される

DOMツリーが作成されるので、JavaScript で DOM API を使って操作ができる ということになります。
試しに、マウスオーバー/マウスアウト で circle 要素の色が変わる操作をしてみます。

<body>
  <svg width="300" height="300">
    <circle cx="100" cy="100" r="50" fill="tomato" />
  </svg>
  <script>
    const svgElement = document.getElementsByTagName('svg')[0];
    const circleElement = svgElement.getElementsByTagName('circle')[0];
    const changeColor = (hex) => circleElement.style.fill = hex;

    circleElement.addEventListener('mouseover', changeColor.bind(this, 'gold'));
    circleElement.addEventListener('mouseout', changeColor.bind(this, 'forestgreen'));
  </script>
</body>

f:id:jinseirestart:20191218011754g:plain
javascript を使って SVG にインタラクションを与える

このように、JavaScriptCSS を使って制御を行い場合は インラインSVG で記述します。

4. 外部メディアとして埋め込む

あまり使う機会はないかと思いますが、object要素、embed要素を使って外部メディアとして埋め込むことが可能です。

▼ index.html

<body>
  <object data="circle.svg" type="image/svg+xml">代替えコンテンツ</object>
  <embed src="rect.svg" type="image/svg+xml">
</body>

▼ circle.svg

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">
    <circle cx="100" cy="100" r="50" fill="tomato" />
</svg>

▼ rect.svg

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">
    <rect x="100" y="100" width="100" height="100" fill="skyblue"  />
</svg>

※ 分かりやすいように、object要素とembed要素の背景色に薄いグレーをつけています。

f:id:jinseirestart:20191210090436p:plain
表示結果

ネームスペースがない場合

ちなみにこの時、svgにネームスペースを記述しないと描画されません。

▼ circle.svg名前空間を削除

<svg width="300" height="300">
    <circle cx="100" cy="100" r="50" fill="tomato" />
</svg>

f:id:jinseirestart:20191210091241p:plain
ネームスペースがない場合の表示結果

object要素、embed要素にサイズ指定がある場合

下記のように、object要素、embed要素にwidth、heightのサイズ指定がある場合、そちらが優先されます。
svgのサイズは300pxを指定していましたが、表示結果は 500px x 500px600px x 600px となっているのが分かります。

<object data="circle.svg" type="image/svg+xml" width="500" height="500">代替えコンテンツ</object>
<embed src="rect.svg" type="image/svg+xml" width="600" height="600">

f:id:jinseirestart:20191210092105p:plain
object要素、embed要素にサイズ指定がある場合の表示結果

まとめ

  • SVG は画像でもありテキストファイルでもある
  • 基本的には IE9 以上, android 3 以上から使える
  • インラインで使う以外は SVG名前空間の宣言が必須
  • viewport と viewbox の概念がある
  • 埋め込み方法は複数ある
    • img要素で画像として読み込む
    • CSSで背景画像として読み込む
    • インラインで読み込む
      • DOMツリーが生成されるので JavaScript でDOM操作ができる
    • object要素、embed要素で外部ファイルとして読み込む

参考

bindActionCreators を使うと何がいいのか実際コードを書いて理解する

前回の記事で触れた bindActionCreators ですが、今まで使ったことがないので簡単なカウンターアプリを作って、実際に使ってみて一体何がいいのかを確認してみました。

  • カウンターアプリ ver.1
    • コード(ファイル名押下でコード展開)
      • redux
      • container component
      • presentational component
      • エントリーポイント
    • Action Creators だけのオブジェクトを渡す
    • dispatch を引数に取った関数を定義
    • bindActionCreatorsを使った方法
  • カウンターアプリ ver.2
  • まとめ
続きを読む

【React Redux】mapStateToProps の公式ドキュメント訳

React-reduxの公式ドキュメントを久しぶりに見てみると、いろいろと更新されていたので、ちゃんと読みこむことをしています。 今回、connect を使って store とコンポーネントを接続する際に使用する mapStateToProps についての下記ドキュメントを google 翻訳の力で訳したので、自分用にメモ。

react-redux.js.org

続きを読む

React Context APIを理解する

ここしばらくフロントの勉強が疎かになっており、会社での立場に危機感(?)を感じたので、現実から逃げずにちゃんと勉強していくことにしました。
今回は 下記公式ドキュメントを元に Context API について理解したいと思います。

ja.reactjs.org

  • Context APIの使い所
  • サンプル完成版
  • まとめ、感想
続きを読む

名前付け大全を読んだメモ

WEB+DB PRESS VOL.110 の特集「設計も、実装も、ここから始まる!名前付け大全」を読んだメモです。

  • 第1章 「良い名前」とは何か
    • なぜ名前付けが重要なのか
    • 悪い名前の問題
      • 理解が困難
      • 勘違いが起こる
      • 変更が難しい
      • 読みにくい
    • なぜ名前はあるのか
  • 第2章 名前付けの理論
    • 良い名前とは
    • 適切な名前とは
    • 名前の意味と挙動の不一致 3つパターン
    • シンプルさを保つ:適切な名前の基準の一つ
    • 正しい書き方
  • 第3章名前付けの実践
    • パターン1. 名前の意味と挙動がずれている
    • パターン2. 名前の意味と挙動がずれている
    • パターン3. 名前の意味が広すぎる
    • ケーススタディ1:安易な単語を選ぶ
      • check は真偽がどちらかよく分からない
    • ケーススタディ2:重要な単語を不用意に使ってしまう
      • スコープなしで重要な単語を使ってしまう
      • 役割が抜けている
    • ケーススタディ3:実装変更により、既存の名前の意味が変わってしまう
    • もうひとつの基準:シンプル
  • 第4章 英語の壁の克服
    • 品詞
    • 時制・相・法助詞
    • 語彙
    • スペリング
    • 誤読・誤解を防ぐ配慮
  • 第5章 さらなる効率化の手法
  • 読んだ感想
続きを読む

【webpack速習】vol.13: Build Performance

下記ページのざっくりとした翻訳。

webpack.js.org

  • General
    • Stay Up to Date(最新に保つ)
    • Loaders
    • Bootstrap
    • Resolving
    • Dlls
    • Smaller = Faster
    • Worker Pool
    • Persistent cache(永続キャッシュ)
  • Development
    • Incremental Builds
    • Compile in Memory
    • stats.toJson speed
    • Devtool
    • Avoid Production Specific Tooling(production 固有のツールを避ける)
    • Minimal Entry Chunk
    • Avoid Extra Optimization Steps(余分な最適化手順を避ける)
    • Output Without Path Info
    • Node.js Version
    • TypeScript Loader
  • Production
    • Multiple Compilations
    • Source Maps
  • Specific Tooling Issues(特定のツールのイシュー)
    • Babel
    • TypeScript
    • Sass
続きを読む