SVG2で検討されているプロパティ
CSS Property Advent Calendar 2013の12日目の記事です。
もともと:futureや:pastなどを考えていたのですが、9日目にTime-dimensional擬似クラスについて調べてみたで書かれています*1ので、今日はSVG 2で検討されているプロパティを2つ見てみます*2。
paint-orderプロパティ
SVGの描画モデルでは、図形やテキストは、まずfillが描画され、次にstrokeが描画され、その上にmarkersが描画されます(SVG 1.1ではRendering ModelのPainting shapes and textを参照)。
ですが、時と場合によってはこの順番を変えたい時があります。特にfillとstrokeの順番を変えたいときがあります。strokeは、strokeの中心がオブジェクトの縁(アウトライン)にあうように描画されるので、太くすればするほど内側にも食い込んできます。そのためテキストに太めのstrokeをつけたい場合には、大きなstroke-widthを指定するとfillがstrokeで隠れてしまう、というとても残念な結果になります。
これを回避するには、fillだけ指定した要素の後ろに、strokeを指定した要素をもう1つおいたり、フィルターを使ったりしてきました。
<!-- use要素を使ってテキストを重ね書き -->
<use xlink:href="#text" style="fill:none; stroke:#fff; stroke-width:8px; ..." />
<text x="160" y="192" id="text" style="fill:#000">World Wide Web</text>
<!-- filterを使ってstrokeのようなものをつける -->
<defs>
<filter id="filter">
<feMorphology in="SourceAlpha" operator="dilate" radius="3" result="morph" />
<feFlood style="flood-color:#fff" result="flood" />
<feComposite in="flood" in2="morph" operator="in" result="composite" />
<feMerge>
<feMergeNode in="composite" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<text x="160" y="256" style="fill:#000; filter:url(#filter);">World Wide Web</text>
しかしSVG 2では、paint-orderプロパティによって描画の順番を変えることができるようになる見込みです。現在のところ、このプロパティには描画したい順番にキーワード(fill、 stroke、markers)を記述します。記述しなかったプロパティは、fill、stroke、markersの順に描画されるので、strokeを一番最初に描画して残りは通常どおりで良い、という場合にはpaint-order:stroke;と記述すれば十分です。
<!-- SVG 2ではpaint-orderプロパティを指定するだけ -->
<text x="160" y="320" class="stroke" style="paint-order:stroke; fill:#000 stroke:#fff; stroke-width:8px; ...">World Wide Web</text>
このpainte-orderプロパティはGecko(Bug 838805)とBlink(Issue 223766)で実験的にサポートされています。Geckoではsvg.paint-order.enabledをtrueに、Chromeでは「試験運用版のウェブ プラットフォームの機能を有効にする。」必要があります。
vector-effect
SVGではオブジェクトを拡大したり縮小したりといったことが簡単にできます。これまではSVGではオブジェクトの全てが一律に拡大・縮小されてきましたが、SVG 2では拡大縮小してもstrokeを一定に保つことができるようになる見込みです。具体的にはSVG Tiny 1.2にもあるvector-effectプロパティを使います。strokeを一定に保ちたいオブジェクトにvector-effect: non-scaling-stroke;を指定します。
これがどう役に立つのかですが、こういう例はどうでしょうか。strokeだけ指定された星を画面上にたくさん配置します。この時、それぞれの星は大きさが異なりますがstrokeは一定にしたいとしましょう。GUIで例えるならば、画面上にスタンプで星をはりつけていくイメージです。そして、適当にグループ化を行い、その後拡大・縮小を行ったものと考えてください。
ともあれ、大きさが異なるだけであれば星の形は1つだけ定義して、後はクローンを配置しておけば良くなります。
<defs>
<path id="star" d="..." style="stroke:#fff; strok-width:3px;" />
</defs>
<g>
<use xlink:href="#star" x="..." y="..." />
<g transform="scale(0.5)">
<use xlink:href="#star" x="..." y="..." />
<g transform="scale(1.25)">
<use xlink:href="#star" x="..." y="..." />
</g>
</g>
<use xlink:href="#star" x="..." y="..." transform="scale(0.75)" />
</g>
ところが、単純にクローンを配置するだけでは拡大・縮小(transformのscale)の影響を受けてstrokeの太さが変わってします。しかし、vector-effect: non-scaling-stroke; を指定するとstrokeの太さは拡大・縮小の影響を受けません。
<defs>
<path id="star" d="..." style="vector-effect: non-scaling-stroke; stroke:#fff; strok-width:3px; " />
</defs>
自分で書いていてあまり良いユースケースではないなあと思いますが、ともあれstrokeを一定に保つことができます。
さて、このvector-effectプロパティはGecko(Bug 528332)とWebKit(Bug 31438)およびWebKitから派生したBlinkでサポートされています。
おわりに
SVG 2では、ここで挙げた以外の機能の追加も検討されており、既存のプロパティの拡張も検討されています。例えば、fillやstrokeプロパティに複数の値をカンマ区切りで指定して、fillやstrokeを重ね塗りすることもできる(本稿執筆段階ではSVG2 Editor's Draftの11.2. Specifying paintにあります)ようになる見込みです(SVG 1.1などではfillやstrokeに空白区切りでフォールバックを複数指定することはできます)。
またフィルタやマスク、合成とブレンディングはFXTFの仕様を参照する形になる方向ですので、利用できるプロパティや値も増えるでしょう。
- Filter Effects Module Level 1 Editor's Draft
- CSS Masking Module Level 1 Editor’s Draft
- Compositing and Blending Level 1 Editor's Draft
来年も、そしてそれ以降もSVG 2の動向が楽しみですね。