モードの変更

SVG pointer-events 2017

Advent Calendar
CSS
SVG

SVG Advent Calendar 2017の 20 日目。

pointer-events: none については過去書いたとおり、なかなかどうして、好きすぎて困っている。

また、pointer-events プロパティーが大好きなみなさんなら、これが SVG 由来のものだというのは当然ご存知だろう。HTML の要素に指定が有効な値は実質 autonone だけだが、SVG の要素についてはその限りではない。MDN を見ると以下の値がある

これらの値によってポインターイベントのターゲットにどのように変化するのか、ひとまず pointer-events プロパティーに関わる SVG の特徴を理解する必要がある。

塗りと線

SVG の図形は概ねベクターツールのそれと同じで、座標・次の座標へつながるときの向き・向きの強さで表せる。

繋がれた座標の連続は「線」と呼ばれる。線の始点と終点を結んだ領域は「塗り」と呼ばれる。それを SVG に変換すると「塗り」は fill、「線」は stroke となる。

可視性

SVG は visibility プロパティーで可視か不可視かを指定できる。CSS と同じく visiblehidden を値に持つ。visibility = visible の時は可視、visibility = hidden の時は不可視となる。

塗りと線に指定できる値

概ねCSS の<color>型と同じ。厳密には<paint>型なのだが、実質的に<color>型という解釈でいいと思う。

https://www.w3.org/2011/07/29-svg-minutes.html#item02 https://triple-underscore.github.io/SVG11/types.html#DataTypeColor

SVG の装飾方法

SVG にスタイルを当てる方法はだいたい3つある。フィルターやマスクなど考えるとその限りではないが、まぁだいたい3つでいいと思う。

<!-- style属性での指定 -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="30" style="fill: gold; stroke: black; stroke-width: 2" />
</svg>
<!-- style要素での指定 -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <style>
    circle {
      fill: gold;
      stroke: black;
      stroke-width: 2
    }
  </style>
  <circle cx="50" cy="50" r="30" />
</svg>
<!-- プレゼンテーション属性での指定 -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="30" fill="gold" stroke="black" stroke-width="2" />
</svg>

(大まかに言って)このいずれかの装飾で、可視性/塗り/線を設定する。

早見表

そして pointer-events プロパティーと可視性/塗り/線の関係は次の通りとなる。

pointer-events 値\依存する項目 visibility 値 fill 値 stroke 値 簡単な解説
auto visible none 以外 none 以外 visiblePainted と同じ
none -- -- -- 何もターゲットにならない
fill -- -- -- 塗り部分がターゲット
stroke -- -- -- 線部分がターゲット
all -- -- -- 塗りと線がターゲットになる
painted -- none 以外 none 以外 値が none 以外なら塗りも線もターゲット
visible visible -- -- 可視であれば none 値でも塗りと線がターゲットになる
visibleFill visible -- -- 可視であれば none 値でも塗りがターゲット
visibleStroke visible -- -- 可視であれば none 値でも線がターゲット
visiblePainted visible none 以外 none 以外 可視でかつ none 値以外の塗りと線がターゲット

pointer-events に指定できる値は他に inherit があるが、これはただの継承なので表には含めない。

だいたいは fillstroke の値には左右されないが、 painted / visiblePainted のときは none 以外でないといけなくなることがわかる。

none と transparent と opacity と visibility

visibility:hidden 以外でも「見えない」指定は可能だ。色指定なしの none、透明色指定の transparent、全透過の opacity: 0 がある。

しかし仕様によれば transparentopacitypointer-events プロパティーの挙動には影響を与えない。影響を与えるのは「色指定あるなし」と「可視性あるなし」のみということだ。

実食

仕様をあれこれ説明してもしっくりこないと思うのでさっさと触っていこうと思う。SVG で fill と stroke が色付きと none の 4 パターンの path 要素を用意し、プルダウンで pointer-eventsvisibilityopacity を切り替えられるサンプルを作った。path 要素あたりをクリックし、イベントが制限されていなければ黄色いエリアに「Clicked!」と文字が出る(その後消える)。

実装ロジックとしては、プルダウンを選択するとそれぞれのプレゼンテーション属性値が各 SVG へ書き込まれる仕組みになっている。

触ってみると気づくことがある。「fill = none のみ」とか「stroke = none のみ」をターゲットにした pointer-events の制御ができない。これは仕様にないので仕方がない。しかし次の 3 点は仕様と違っておかしい。

仕様とはいったい? 特に3つ目は不思議な動きをする。これに visibility = hidden してみると、期待通り fill = none / stroke = none な SVG はクリックが発火しなくなるのだ。paintedvisibility の値で挙動が変わらないはず。手元の Google Chrome 63、Safari 11.0、Firefox 57.0.1 で確認したがいずれも同じだった。

他の値の組み合わせはどうやら仕様通りに実装されていそうだった。全部のブラウザでは見ていないので何か差があるかもしれない。

誰か知っていることがあったら教えて欲しい。


SVG 怖くなってきた。