PerfectVector
著者: Irene Kim2 分で読める

SVGのパターン単位:繰り返すモチーフを適切なサイズに保つ

patternUnits、patternContentUnits、viewBoxでSVGパターンの間隔とモチーフのサイズを制御します。形状のリサイズとグループ全体の拡大縮小を比較します。

目次

形状の寸法を変えてもSVGパターンの繰り返し間隔を一定にするには、patternUnits="userSpaceOnUse"と数値のタイル幅・高さを使います。タイル内の画像は、patternContentUnitsやパターンのviewBoxで別に制御します。

小さなモチーフで細いバッジと幅広いバナーの両方を塗る場合、この区別が重要です。バナーにコピーを増やしたい、コピー間の隙間を広げたい、モチーフを伸ばしたいなど、目的ごとに座標の選択が異なります。バナーのグループ全体を拡大縮小すると、また別の結果になります。

モチーフがすでにSVGのパスなら、そのパスを保持します。ベクター化が必要なのは、元データがラスター画像しかない場合の前段階です。

タイルとその画像を分ける

パターンには、繰り返す矩形タイルと、その中に描く内容があります。patternUnitsはタイルのx、y、width、heightを制御します。patternContentUnitsは、パターンにviewBoxがない場合に内容の座標を制御します。

設定制御するもの既定値役立つ選択
patternUnitsタイルの位置と寸法objectBoundingBox対象の現在のユーザー座標で数値の間隔を指定するならuserSpaceOnUse
patternContentUnitsタイル内のパスや形状の座標userSpaceOnUseモチーフ寸法を対象の境界に依存させるならobjectBoundingBox
パターンのviewBox各タイルに収める座標矩形なし0 0 40 40など、再利用できるモチーフの座標系

objectBoundingBoxでは、幅.25は塗るオブジェクトの境界ボックスの幅の4分の1を意味します。モチーフの幅の4分の1ではありません。幅120単位の矩形には30単位、幅240単位の矩形には60単位のタイルができます。

内容の既定値はuserSpaceOnUseのままです。そのため、patternUnitsだけを変えると、モチーフのサイズを変えずに間隔が変わる場合があります。一緒に変わると思わず、両方の属性を意図して設定します。

同じ葉の4つの版を比較する

この例用に葉のパスを描き、SVGをブラウザーで描画しました。対象の2つの矩形はどちらも高さ80単位で、幅は120と240です。スクリーンショットでは元の形状の周囲にラベルと背景を追加しています。SVGのデモであり、PerfectVectorの変換結果ではありません。

細い矩形と幅広い矩形で、固定タイル、相対タイル、相対モチーフ座標、viewBoxによる上書きを比較する4行のSVGパターンのブラウザー描画
対象を広げると、最初と最後の行では繰り返しが増えます。相対的なタイル幅では4列が維持され、相対的な内容座標では葉も伸びます。

上から順に読みます。

  1. 固定した40 × 40のタイルは、細い矩形で3列、幅広い矩形で6列になります。葉の寸法は変わりません。
  2. タイル幅.25は、両方の対象で4列を保ちます。葉の座標はユーザー単位のままなので、幅広い矩形では葉の間の空間が増えます。
  3. 境界ボックスの内容座標では、対象の幅が2倍になると葉が水平方向に伸びます。対象の高さは同じなので、垂直サイズは変わりません。
  4. 固定した40 × 40のタイルにviewBox="0 0 40 40"を付けると、マークアップにpatternContentUnits="objectBoundingBox"が残っていても、最初の行と同じ結果に戻ります。パターンのviewBoxが優先します。

完全な例を開く

pattern-units.svgとして保存し、ブラウザーで直接開きます。4行には図と同じ定義を使い、ラベルと背景はありません。各矩形の組は、ローカル原点を比較できるよう、移動したグループ内にあります。

<svg xmlns="http://www.w3.org/2000/svg" width="560" height="420" viewBox="0 0 560 420">
<defs>
  <pattern id="fixed" patternUnits="userSpaceOnUse" width="40" height="40">
    <path d="M8 24 Q8 6 30 8 Q30 26 8 24Z" fill="#127f70"/>
  </pattern>
  <pattern id="tile" patternUnits="objectBoundingBox" width=".25" height=".5">
    <path d="M8 24 Q8 6 30 8 Q30 26 8 24Z" fill="#127f70"/>
  </pattern>
  <pattern id="both" patternUnits="objectBoundingBox" patternContentUnits="objectBoundingBox" width=".25" height=".5">
    <path d="M.04 .30 Q.04 .08 .20 .10 Q.20 .33 .04 .30Z" fill="#127f70"/>
  </pattern>
  <pattern id="box" patternUnits="userSpaceOnUse" patternContentUnits="objectBoundingBox" width="40" height="40" viewBox="0 0 40 40">
    <path d="M8 24 Q8 6 30 8 Q30 26 8 24Z" fill="#127f70"/>
  </pattern>
</defs>
  <g transform="translate(20 20)"><rect width="120" height="80" fill="url(#fixed)"/></g>
  <g transform="translate(220 20)"><rect width="240" height="80" fill="url(#fixed)"/></g>
  <g transform="translate(20 120)"><rect width="120" height="80" fill="url(#tile)"/></g>
  <g transform="translate(220 120)"><rect width="240" height="80" fill="url(#tile)"/></g>
  <g transform="translate(20 220)"><rect width="120" height="80" fill="url(#both)"/></g>
  <g transform="translate(220 220)"><rect width="240" height="80" fill="url(#both)"/></g>
  <g transform="translate(20 320)"><rect width="120" height="80" fill="url(#box)"/></g>
  <g transform="translate(220 320)"><rect width="240" height="80" fill="url(#box)"/></g>
</svg>

fixedパターンから始め、2つ目の矩形の幅だけを変えます。パスを変える前にtileとbothを確認します。こうすると、座標の選択と画像自体を分けて考えられます。パスや色をさらに編集する場合は、SVGの編集ガイドを使ってください。

モチーフ自身の座標がある場合はviewBoxを使う

パターンのviewBoxを使うと、タイルは別のサイズを持ちながら、葉は慣れた描画領域を維持できます。SVGのパターン仕様は、viewBoxとpreserveAspectRatioで描画領域をタイル内へ収めます。

最後の行では、タイルとviewBoxがどちらも40 × 40なので、縦横比の違いはありません。後でタイルを長方形にすると、既定のpreserveAspectRatio="xMidYMid meet"がモチーフの比率を保ち、収めた描画領域を中央に配置します。preserveAspectRatio="none"は、水平方向と垂直方向の独立した拡大縮小を許容します。意図して変形する場合だけ選んでください。

パターンにviewBoxがある間は、patternContentUnitsを変えてもサイズの問題は直りません。この場合、その属性には効果がありません。変えたい部分に応じて、タイル寸法、viewBox、縦横比の規則を変更します。

1つの定義で繰り返しの塗りを描く場合に、パターンが役立ちます。個別に配置するコピーが必要なら、SVGのsymbolとuseインスタンスのほうが直接的に適しています。

矩形のリサイズとグループの拡大縮小は異なる

userSpaceOnUseが固定するのはユーザー座標での間隔であり、永久に一定の画面ピクセルではありません。変換は、パターン塗りを含むその座標を拡大縮小できます。

上のfixed定義で2つの版も開きました。最初の矩形はwidth="240"です。2つ目はwidth="120"を保ち、transform="translate(20 120) scale(2 1)"のグループ内にあります。文書内ではどちらも画面上で240単位を占めますが、最初は葉が6列、変換したほうは横に伸びた3列でした。

レスポンシブな画像の問題を調べる場合に、この区別を使います。

  • 繰り返しを増やすには、座標の倍率を変えずに対象の形状を大きくします。
  • 構図全体を大きくするには、グループを拡大し、パターンの見た目も拡大されると考えます。
  • ページレイアウトがルートSVGの表示サイズを変える場合は、パターン属性を原因とする前に、ルートのviewBoxの対応付けを確認します。

SVGの座標系仕様は、ユーザー座標に適用する変換を説明しています。アプリ間で差がある場合は、まずSVGの文書寸法を確認します。パターン単位だけでは、物理的な出力サイズは決まりません。

繰り返す前に独自のモチーフを準備する

モチーフがPNGやJPGしかない場合は、PerfectVectorで繰り返し用のSVG形状を復元できます。モチーフをベクターへ変換し、エディターで結果を開き、輪郭、小さな隙間、不要な背景形状を確認してから、パターン内へ配置します。

モチーフのSVGマスターを別に保持します。コピーの周囲にタイルを作り、細い対象と幅広い対象の両方でテストします。既存のベクター画像は、直接この編集工程へ進めます。単純な幾何学的マークは手で描き直すほうが速い場合があり、写真は複雑なパス一式へトレースするより、画像のまま保持するほうがよい場合があります。

ブラウザー描画だけでは、すべてのデザインアプリがパターン定義を保持するとは判断できません。保存したファイルを実際の対象環境で開き直し、繰り返し間隔とモチーフの形を確認します。また、繰り返しの塗りは、見えている葉ごとの独立した編集可能なコピーを作りません。SVGファイルのガイドでは、見た目だけでなく文書構造が重要な理由を説明しています。

ファイルを渡す前に、各fill="url(#...)"が存在する一意のパターンIDを参照し、タイル寸法が正で、モチーフが意図したタイルに収まるか確認します。SVGパターンは通常、タイルの境界で内容を切ります。そのため、端をまたぐ葉には、はみ出しが見えると想定するのではなく、意図した繰り返し設計が必要です。

よくある質問

間隔は変わったのに、葉のサイズが同じなのはなぜですか? patternUnitsはタイル寸法、patternContentUnitsは画像の座標を制御します。内容が既定のユーザー空間のままなら、境界ボックスのタイルは葉をリサイズせずに間隔を変えられます。

patternContentUnitsが効かないように見えるのはなぜですか? パターンにviewBoxがあるか確認してください。ある場合は、それが内容の座標の対応付けを定義し、patternContentUnitsには効果がありません。

userSpaceOnUseは画面上のパターンサイズを維持しますか? 対象の現在のユーザー座標系で、数値のタイル寸法を維持します。グループの拡大縮小や、ルートSVGの座標からビューポートへの対応付けを変えると、表示サイズは変わる場合があります。

参考資料

  1. MDN — patternUnits — タイル形状の座標と、既定の境界ボックスを定義しています。
  2. MDN — patternContentUnits — 内容座標とviewBoxによる上書きを定義しています。
  3. W3C — SVGのパターン — タイルへの配置、縦横比の挙動、パターンのクリッピングを説明しています。
  4. W3C — SVGの座標系 — グループ拡大縮小の基礎となるユーザー座標の変換を定義しています。

再利用したいモチーフがラスターしかない場合は、画像をSVGパスに変換し、復元した輪郭を確認してから、完成した繰り返しを作る前に両方の対象サイズでテストしてください。

ブログのその他の記事

編集しやすい
よりきれいなSVGから始めましょう