PerfectVector
著者: Irene Kim2 分で読める

SVGのpointer-events:画像に合うクリック領域を作る

塗り、ストローク、穴、別のヒット領域でSVGのクリック範囲を制御します。イベントの対象を検証し、キーボード操作は標準のボタンやリンクに持たせます。

目次

SVGのpointer-eventsは、画像のどの部分がポインターイベントの対象になるかを制御します。同じイラストでも、塗り形状、細いストローク、空の穴は異なる反応をする場合があります。読者が期待する操作に合わせてヒット領域を設定し、色のある部分だけでなく空の部分も慎重にテストします。

このガイドは、選択できる図、クリック可能なエンブレム、ボタン内のアイコンなど、Webインターフェースの画像向けです。SVGに使えるパスがすでにあるなら、操作コードを直接修正します。ベクター化が必要なのは、編集可能な形状がまだPNGやJPG内にある場合だけです。

クリックを受ける要素から始める

SVGの既定値autoは、visiblePaintedと同じように動作します。見える形状では、fillがnoneでなければ塗り、strokeがnoneでなければストローク上が対象になります。SVGの操作仕様が、これらのヒット判定規則を定義しています。

そのため、一見壊れたアイコンでも、リスナーが輪郭上では動き、空の中心では反応しない場合があります。ブラウザーは形状を判定し、周囲の矩形内のすべての点が同じ意味だとは想定しません。

この手順で役立つ選択肢は次のとおりです。

値用途
auto見える描画済みの塗りとストロークで対象を決めます
stroke開いた線も含め、ストローク領域を対象にします
fill塗りがnoneでも形の内部を対象にします
all描画や可視性を条件とせず、塗りとストローク領域を対象にします
noneこの要素をポインターの対象から除外します

allは「SVGビューポートのすべての点」ではありません。依然として要素の形状を指します。繊細な画像の周囲の特定の矩形を反応させたい場合は、その矩形を意図して作ります。

透明な塗りと塗りなしも区別します。fill="transparent"も塗りの値ですが、fill="none"は塗りをなくします。不透明度だけでは、オーバーレイにクリックを無視させる確実な方法になりません。

塗り、穴、開いたストロークを試す

独自の手書き形状を持つ小さなインラインSVGの実験ページを作りました。矩形の穴のある青い複合パス、オレンジの開いたストローク、別の透明な対象上に置いたそのストロークのコピーがあります。学習用の例で、PerfectVectorの変換結果ではありません。

青いリング、開いたオレンジのストローク、別のヒット領域、記録されたクリック対象と2回のキーボード操作を示すブラウザーテスト
リングとストロークのクリックは各パスに当たります。別の対象を追加するまでは、空の領域はSVGのステージに当たります。標準のボタンはEnterとSpaceにも反応します。

ブラウザーテストでは、青い帯のクリックはring、空の中心は包含するSVGのring-stageと記録されました。オレンジの線はtrail、頂点の下の空間はstroke-stageでした。3つ目のパネルでは、両方の位置がhitでした。

青いパスは2つの矩形サブパスとfill-rule="evenodd"を使います。

<svg id="ring-stage" viewBox="0 0 240 180">
  <path id="ring" fill="#2874c8" fill-rule="evenodd"
    d="M30 20H210V160H30Z M85 60H155V120H85Z" />
</svg>

偶奇の塗り規則では、内側の矩形は塗り領域の外です。実際の穴です。上に重ねた白い矩形なら、別の描画形状として固有のヒット動作を持ちます。形状自体が誤っている場合は、イベント規則を変える前にSVGの穴の修復ガイドを使います。

2つ目のパネルの開いたストロークは次のとおりです。

<svg id="stroke-stage" viewBox="0 0 240 180">
  <path id="trail" d="M30 140L120 35L210 140"
    fill="none" stroke="#db704c" stroke-width="12"
    pointer-events="stroke" />
</svg>

簡単に試すには、どちらかのコードをHTMLへ置き、その後に次の記録処理を置きます。SVGにwidth="360" height="270"などの見えるサイズを与えます。

<output id="result" aria-live="polite">Click the artwork.</output>
<script>
  const stage = document.querySelector('svg');
  const result = document.querySelector('#result');
  stage.addEventListener('click', (event) => {
    result.textContent = `Target: ${event.target.id}`;
  });
</script>

描画領域、空の内部、画像外の隅をクリックします。event.targetの記録で、パスのヒットと、単にSVGコンテナーへ届いたクリックを区別できます。この例は対象選択のテストで、完成した操作部品ではありません。

画像を太くせずヒット領域を加える

オレンジの線の周囲全体で線を選択させたい場合を考えます。見えるストロークを太くすると、イラストが変わります。別の対象なら、操作領域に固有の形状を使えます。

<svg id="hit-stage" viewBox="0 0 240 180">
  <rect id="hit" x="20" y="20" width="200" height="140"
    fill="transparent" pointer-events="all" />
  <path d="M30 140L120 35L210 140"
    fill="none" stroke="#db704c" stroke-width="12"
    pointer-events="none" />
</svg>

矩形は画像の背後にあります。オレンジのパスはポインターの対象にならないため、その上から矩形へクリックが届きます。座標で意図した対象を明示し、見えるパスデータは2つ目のパネルと同じままです。

図の領域や、指しにくい細い線に役立ちます。無関係な操作部品と対象を重ねず、2つの領域が接する場所の動作を決めます。大きな不可視形状も、見える形状と同様に隣のクリックを奪う場合があります。

1つの操作を行う単純なアイコンなら、SVG矩形を加えず、標準のHTMLボタンで必要な対象を作れる場合が多くあります。

キーボード操作は操作部品に持たせる

ポインターの対象設定は、ラベル、キーボード操作、ボタンの意味を提供しません。単一操作のアイコンは名前のあるHTMLボタンに入れ、画像は装飾にします。

<button id="select-trail" type="button">
  <svg aria-hidden="true" viewBox="0 0 24 24"
    width="24" height="24" style="pointer-events: none">
    <path d="M3 20L12 4L21 20" fill="none"
      stroke="currentColor" stroke-width="3" />
  </svg>
  Select trail
</button>
<output id="selection" aria-live="polite"></output>
<script>
  const button = document.querySelector('#select-trail');
  const selection = document.querySelector('#selection');
  button.addEventListener('click', () => {
    selection.textContent = 'Trail selected';
  });
</script>

標準のbutton要素が操作動作を提供し、見える文字が名前になります。見えるフォーカス表示を残します。別のページへ移動する操作には、実際のリンクを使います。

実験ページでは、Tabでボタンへフォーカスし、EnterとSpaceでそれぞれ操作できました。実際のインターフェースでもそのキーをテストします。複数の独立操作のある図には、その操作に適したキーボード設計が必要です。図全体を囲む1つのボタンでは、すべての操作を表せません。

pointer-events: noneは無効状態でもありません。本来フォーカスできる操作部品を、キーボード移動から除外しません。MDNはキーボードフォーカスとイベント伝播を説明しています。子孫は再び対象になるよう設定でき、そのイベントは親のリスナーを通る場合があります。ボタンを無効にするには、標準のdisabled属性を使います。

開始画像がPNGの場合

平面的なPNGやJPGしかなく、インターフェースに独立して編集可能な形状が必要なら、PerfectVectorの画像をベクターに変換する手順でSVG候補を準備できます。元画像と比較し、重要な穴と領域を確認して、別の操作対象を持たせる部分を決めます。

トレースは形状を提供します。意味のあるID、操作ハンドラー、名前、フォーカス動作、意図したヒット領域はアプリ側に必要です。トレースした見た目の輪郭は、ユーザーがクリックするべき領域より細かい場合があります。小さなUIアイコンには、手動の描き直しや既存のベクターマスターが管理しやすい場合があります。PNGアイコンの準備ガイドは、復元画像をUIキットへ入れる前の確認を説明しています。

操作部品内の装飾アイコンなら、CSSマスクアイコンが色の挙動に適する場合があります。操作は周囲の部品が担います。ベクター化ガイドは、そもそもパスの復元が役立つ場合を扱っています。

公開前に意図した領域を検証する

大きなエディタープレビューだけでなく、実際の表示サイズで試します。

  1. 塗り領域、ストローク、各穴、空の隅をクリックします。
  2. 誤った操作が起きたらイベント対象を調べます。
  3. ポインターを奪う透明矩形やオーバーレイを確認します。
  4. 隣の対象が予期せず重ならないか確認します。
  5. 適切な場所でTab、Enter、Spaceを使い、フォーカスを表示します。
  6. 対応するデバイスでタッチ操作をテストします。

実験ページは1つのブラウザーでこの特定形状を検証しています。マスク、クリッピング、フィルター、複雑な読み込み画像でのすべてのブラウザーの動作を証明しません。デザインにそれらがあれば、自分のテストへ加えます。

編集可能な形状がないなら、PerfectVectorで元画像を試し、輪郭と穴を確認します。画像が正しくなった後、操作領域を別途定義してテストします。

よくある質問

SVGの輪郭をクリックしたときだけ反応するのはなぜですか? 既定のSVGのポインター動作では、塗りのない形状は描画したストローク上だけが対象になる場合があります。塗りの値と意図した操作を確認します。空白も同じ操作を起動するなら、意図したヒット領域や周囲の標準部品を使います。

pointer-events="all"はSVG全体をクリック可能にしますか? 描画や可視性の値に関係なく、要素の塗りとストローク領域を対象にします。SVGビューポート全体が自動で対象になるわけではありません。その領域が必要なら、明示的な形状か周囲の操作部品を使います。

透明な矩形はクリックを受け取れますか? はい。透明だから形状や塗りがないわけではありません。適切なpointer-events値の透明矩形は意図したヒット領域に使えますが、誤ってクリックを奪う場合もあります。

画像をベクター化すると、アクセシブルなボタンができますか? いいえ。ラスターから編集可能な形状を作れますが、名前、キーボード動作、操作ハンドラー、フォーカス、操作領域はインターフェースで実装・検証する必要があります。

参考資料

  1. W3C — SVG 2のスクリプトと操作 — ポインターの対象とpointer-events値が使う形状を定義しています。
  2. W3C — SVG 2の描画 — 塗り規則がパスの内部と穴を決める方法を定義しています。
  3. MDN — pointer-events — 対象、伝播、継承、キーボードフォーカスの制限を説明しています。
  4. MDN — button要素 — 標準ボタンの動作、名前、無効状態を説明しています。

ブログのその他の記事

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