ポインタイベントプロパティとのSVG相互作用の管理

公開: 2022-03-10
簡単な要約↬pointer pointer-eventsプロパティを使用して、SVG画像の対話性を形成する方法、つまり、ドキュメントのどの部分がクリック、タッチ、またはタップを受け取ることができるかを制御する方法を見てみましょう。

下のSVG画像をクリックまたはタップしてみてください。 ポインタを正しい場所(影付きのパス)に置くと、SmashingMagazineのホームページが新しいブラウザタブで開かれるはずです。 空白をクリックしようとすると、代わりに本当に混乱する可能性があります。

CodePenのTiffanyBrown(@webinista)によるペンアメジストを参照してください。

CodePenのTiffanyBrown(@webinista)によるペンアメジストを参照してください。

これは、SVG画像内のリンクを含む最近のプロジェクトで直面したジレンマです。 画像をクリックすると、リンクが機能することがありました。 他の時にはそうではありませんでした。 紛らわしいですよね?

何が起こっているのか、そしてSVGが修正を提供するかどうかについてもっと知るために、私はSVG仕様に目を向けました。 答え: pointer-events

ジャンプした後もっと! 以下を読み続けてください↓

DOM( D ocument O bject M odel)ポインターイベントと混同しないように、 pointer-eventsはCSSプロパティとSVG要素属性の両方です。 これにより、SVGドキュメントまたは要素のどの部分が、マウス、トラックパッド、指などのポインティングデバイスからイベントを受信できるかを管理できます。

用語に関する注意:「ポインタイベント」は、デバイスに依存しない、ユーザー入力用のWebプラットフォーム機能の名前でもあります。 ただし、この記事では、およびpointer-eventsプロパティの目的で、「ポインターイベント」というフレーズにはマウスイベントとタッチイベントも含まれます。

箱の外:SVGの「形状モデル」

HTMLでCSSを使用すると、HTMLにボックスレイアウトモデルが適用されます。 ボックスレイアウトモデルでは、すべての要素がその内容の周りに長方形を生成します。 その長方形は、インライン、インラインレベル、アトミックインラインレベル、またはブロックの場合がありますが、それでも4つの直角と4つのエッジを持つ長方形です。 リンクまたはイベントリスナーを要素に追加すると、インタラクティブ領域は長方形の寸法と一致します。

インタラクティブ要素にclip-pathを追加すると、そのインタラクティブ境界が変更されます。 つまりa要素に六角形のclip-pathを追加すると、クリッピングパス内のポイントのみがクリック可能になります。 同様に、スキュー変換を追加すると、長方形が菱形に変わります。

SVGにはボックスレイアウトモデルがありません。 ご覧のとおり、SVGドキュメントがHTMLドキュメントに含まれている場合、CSSレイアウト内で、ルートSVG要素はボックスレイアウトモデルに準拠します。 その子要素はそうではありません。 その結果、ほとんどのCSSレイアウト関連のプロパティはSVGには適用されません。

その代わりに、SVGには「形状モデル」と呼ぶものがあります。 リンクまたはイベントリスナーをSVGドキュメントまたは要素に追加する場合、インタラクティブ領域は必ずしも長方形である必要はありません。 SVG要素にバウンディングボックスがあります。 バウンディングボックスは、次のように定義されます。要素とその子孫を完全に囲む、その要素のユーザー座標系の軸に位置合わせされた最もぴったりと合う長方形。 ただし、最初は、SVGドキュメントのどの部分がインタラクティブであるかは、どの部分が表示および/またはペイントされているかによって異なります。

ペイントされた要素と目に見える要素

SVG要素は「塗りつぶす」ことができますが、「ストローク」することもできます。 塗りつぶしとは、図形の内部を指します。 ストロークはその輪郭を指します。

合わせて、「塗りつぶし」と「ストローク」は、要素を画面またはページ(キャンバスとも呼ばれます)にレンダリングするペイント操作です。 ペイントされた要素について話すとき、要素に塗りつぶしやストロークがあることを意味します。 通常、これは要素も表示されることを意味します。

ただし、SVG要素は表示せずにペイントできます。 これは、 visibleされている属性値またはCSSプロパティがhidden表示になっている場合、またはdisplaynoneの場合に発生する可能性があります。 要素はそこにあり、理論的な空間を占めています。 私たちはそれを見ることができません(そして支援技術はそれを検出しないかもしれません)。

おそらくもっと紛らわしいことに、要素はペイントせずにvisible visibilityの値を計算して表示することもできます。 これは、要素にストロークと塗りつぶしの両方がない場合に発生します。

アルファ透明度のカラー値(例: rgba(0,0,0,0) )は、要素がペイントされているか表示されているかに影響しません。 つまり、要素にアルファ透明の塗りまたは線がある場合、見えなくてもペイントされます。

pointer-events値の影響を理解するには、要素がいつペイントされるか、表示されるか、またはどちらでもないかを知ることが重要です。

全か無かの法則またはその間の何か:値

pointer-eventsは、CSSプロパティとSVG要素属性の両方です。 その初期値はautoです。これは、ペイントされた部分と表示された部分のみがポインタイベントを受け取ることを意味します。 他のほとんどの値は、次の2つのグループに分割できます。

  1. 要素を表示する必要がある値。 と
  2. そうでない値。

paintedfillstroke 、およびallが後者のカテゴリに分類されます。 それらの可視性に依存する対応物( visiblePaintedvisibleFillvisibleStrokevisible )は、前者に分類されます。

SVG 2.0仕様では、 bounding-box値も定義されています。 pointer-eventsの値がbounding-boxの場合、要素の周囲の長方形の領域もポインタイベントを受け取ることができます。 この記事の執筆時点では、Chrome65以降のみがbounding-boxの値をサポートしています。

noneも有効な値です。 要素とその子がポインタイベントを受信するのを防ぎます。 pointer-events CSSプロパティは、HTML要素でも使用できます。 ただし、HTMLで使用する場合、 autononeのみが有効な値です。

pointer-events値は説明よりもよく示されているので、いくつかのデモを見てみましょう。

ここに、塗りと線が適用された円があります。 塗装され見えます。 円全体がポインタイベントを受信できますが、円の外側の領域は受信できません。

CodePenのTiffanyBrown(@webinista)によってSVGでペイントされたPen Visiblevsを参照してください。

CodePenのTiffanyBrown(@webinista)によってSVGでペイントされたPen Visiblevsを参照してください。

塗りつぶしを無効にして、その値がnoneになるようにします。 ここで、円の内側にカーソルを合わせたり、クリックしたり、タップしたりしようとしても、何も起こりません。 ただし、ストローク領域に対して同じことを行うと、ポインタイベントがディスパッチされます。 fillの値をnoneに変更すると、この領域は表示されますが、ペイントされません。

マークアップに小さな変更を加えましょう。 fill=noneを維持しながら、 pointer-events="visible"circle要素に追加します。

ペン「ポインターイベントの追加方法:すべてがCodePenのTiffany Brown(@webinista)による対話性に影響する」を参照してください。

ペン「ポインターイベントの追加方法:すべてがCodePenのTiffany Brown(@webinista)による対話性に影響する」を参照してください。

これで、ストロークで囲まれたペイントされていない領域がポインタイベントを受け取ることができます。

SVG画像のクリック可能な領域の拡張

この記事の最初からの画像に戻りましょう。 私たちの「アメジスト」は、それぞれがstrokefillを持つポリゴンのグループとは対照的に、 path要素です。 つまり、 pointer-events="all"を追加して1日と呼ぶことはできません。

代わりに、クリック領域を増やす必要があります。 ペイントされた要素と目に見える要素について私たちが知っていることを使用しましょう。 以下の例では、画像マークアップに長方形を追加しました。

CodePenのTiffanyBrown(@webinista)によるSVG画像のクリック領域を拡張するペンを参照してください。

CodePenのTiffanyBrown(@webinista)によるSVG画像のクリック領域を拡張するペンを参照してください。

この長方形は見えませんが、技術的には見えます(つまり、 visibility: visible )。 ただし、塗りつぶしがないということは、塗装されていないことを意味します。 私たちの画像は同じように見えます。 実際、それでも同じように機能します。空白をクリックしても、ナビゲーション操作はトリガーされません。 要素にpointer-events属性を追加a必要があります。 visible値またはall値を使用すると、ここで機能します。

CodePenのTiffanyBrown(@webinista)によるSVG画像のクリック領域を拡張するペンを参照してください。

CodePenのTiffanyBrown(@webinista)によるSVG画像のクリック領域を拡張するペンを参照してください。

これで、画像全体がポインタイベントを受け取ることができます。

bounding-boxを使用すると、ファントム要素が不要になります。 バウンディングボックス内のすべてのポイントは、パスで囲まれた空白を含むポインタイベントを受け取ります。 しかし、繰り返しになりますpointer-events="bounding-box"は広くサポートされていません。 それまでは、未塗装の要素を使用できます。

SVGとHTMLを混在させる場合pointer-events使用

pointer-eventsが役立つ可能性のある別のケース:HTMLボタン内でSVGを使用する。

CodePenのTiffanyBrown(@webinista)によるPenOvxmmyを参照してください。

CodePenのTiffanyBrown(@webinista)によるPenOvxmmyを参照してください。

ほとんどのブラウザ(FirefoxとInternet Explorer 11はここでは例外です)では、 event.targetの値はHTMLボタンではなくSVG要素になります。 開始SVGタグにpointer-events="none"を追加しましょう。

Pen Howのポインターイベントを参照してください:CodePenのTiffany Brown(@webinista)によるSVGおよびHTMLでは使用できません。

Pen Howのポインターイベントを参照してください:CodePenのTiffany Brown(@webinista)によるSVGおよびHTMLでは使用できません。

これで、ユーザーがボタンをクリックまたはタップすると、 event.targetbuttonを参照します。

DOMとJavaScriptに精通している人は、arrow関数の代わりにfunctionキーワードを使用し、 event.targetの代わりにthisを使用すると、この問題が修正されることに気付くでしょう。 ただし、CSSでpointer-events="none" (またはpointer-events: none; )を使用すると、その特定のJavaScriptの癖をメモリにコミットする必要がなくなります。

結論

SVGは、HTMLで使用していたのと同じ種類の対話性をサポートします。 これを使用して、クリックまたはタップに応答するグラフを作成できます。 CSSおよびHTMLボックスモデルに準拠しないリンクされた領域を作成できます。 また、 pointer-eventsを追加することで、ユーザーの操作に応じてSVGドキュメントの動作を改善できます。

SVG pointer-eventsブラウザーサポートは堅牢です。 SVGをサポートするすべてのブラウザーは、SVGドキュメントと要素のプロパティをサポートします。 HTML要素とともに使用すると、サポートの堅牢性が少し低下します。 Internet Explorer 10またはその前身、あるいはOperaMiniのどのバージョンでも利用できません。

この部分では、 pointer-eventsの表面をかじったところです。 より詳細で技術的な扱いについては、SVG仕様をお読みください。 MDN(Mozilla Developer Network)Web Docsは、 pointer-eventsに関するよりWeb開発者向けのドキュメントを、例とともに提供します。