2012年12月19日水曜日

svgの禁じ手?text要素とa要素で文字列の一部をずらす

svg1.1seの仕様書を眺めていて,text要素とa要素の相関についての記述が非常に少ないことが判りました.そこでそれを逆手に取ってちょっと試してみた処,面白い結果が得られたのでまとめてみます.


テキストを表すtext要素


svgにおいて文字列を挿入したい場合,text要素を使います.これはhtmlにおけるdivやspan要素に相当するものとして考えて結構です.この要素にスタイルを設定して様々な文字表現を行うことができます.
svgによる文字列の表示
<svg style="border: 2px outset black; height: 50px; width: 300px;" width="300px">
 <text font-size="20" x="0" y="30">svgによる文字列の表示</text>
</svg>

文字列の一部を表す二つの要素


この時text要素の下に配置できる要素としてtspan要素とa要素があります.この他にもtref要素はaltGlyph要素などがあるのですが割愛します.
  • 部分文字列を表すtspan要素
    text要素が表す文字列の一部に異なるスタイルを設定したい場合,tspan要素を用います.
svgによる文字列の表示
<svg style="border: 2px outset black; height: 50px; width: 300px;" width="300px">
 <text font-size="20" x="0" y="30">svgによる<tspan fill="red">文字列</tspan>の表示</text>
</svg>

  • リンクを表すa要素
    a要素はリンクを表す要素で,htmlにおけるa要素に相当します.通常は図形を表す要素をa要素で囲むことで任意の形をしたリンクを作ることが出来るのですが,text要素の配下とすることで文字列の一部にリンクを挿入することができます.
svgによる文字列の表示
<svg style="border: 2px outset black; height: 50px; width: 300px;" width="300px">
 <text font-size="20" x="0" y="30">svgによる<a fill="blue">文字列</a>の表示</text>
</svg>

いずれも役割は異なるものの,text要素が定めた文字列の一部を表すことに変わりなく,どちらにおいてもスタイルを変更することができます.

では何が異なるのか


さてここからが本題です.このある意味似た二つの要素において決定的に異なる部分があります.それはtransform属性の有効性です.

tspanでは無効となるのですが,a要素では有効とされているのです.a要素には図形をグループ化することがあるため,transform属性が定められているのです.

文字列の一部を正攻法でずらす


ここで一旦この比較から離れて文字列の一部をずらすことを考えてみましょう.

文字列の一部をずらすといったことは,内容を強調する目的でよく行われることですが,svgで実現するのは意外に面倒です.

本来文字列の整列に関わる属性baseline-shiftを使うべきなのですが,この属性はブラウザによって動作しない場合があります.

svgによる文字列の表示
<svg style="border: 2px outset black; height: 50px; width: 300px;" width="300px">
 <text font-size="20" x="0" y="30">svgによる<tspan baseline-shift="5" fill="green">文字列</tspan>の表示</text>
</svg>

従って別の方法を考えねばなりません.この時transform属性が使えるのなら話が早いのですが,tspan要素にはtransform属性が定義されていません.

svgによる文字列の表示
<svg style="border: 2px outset black; height: 50px; width: 300px;" width="300px">
 <text font-size="20" x="0" y="30">svgによる<tspan fill="green" transform="translate(0,-5)">文字列</tspan>の表示</text>
</svg>

従ってこの動作をさせるために次のような設定を行う必要があります.文字の描画位置をずらす位置を表すtspan要素を挿入するのです

ここでは「svgによる文字列の表示」の「文字列」の部分をずらしたいので,ずらす開始文字列「文」と,ずらした直後の文字「の」にdy属性を適用して文字の位置をずらします.

svgによる字列表示
<svg style="border: 2px outset black; height: 50px; width: 300px;" width="300px">
 <text font-size="20" x="0" y="30">svgによる<tspan fill="green"><tspan dy="-5">文</tspan>字列</tspan><tspan dy="5">の</tspan>表示</text>
</svg>

これで動作するようになりはしました.これが現状私が考える最良の解なのですが,文字列の一部を適切に表せていないためいささか記述が冗長です.

a要素のtransform属性を使ってみよう


ではa要素のtransform属性はtext要素内部で有効となるのでしょうか?試してみましょう.

svgによる文字列の表示
<svg style="border: 2px outset black; height: 50px; width: 300px;" width="300px">
 <text font-size="20" x="0" y="30">svgによる<a fill="green" transform="translate(0,-5)">文字列</a>の表示</text>
</svg>

chromeでは動作しませんが,firefoxとoperaではあっさりと動作してしまいました.

考察


なぜこのような結果となるのでしょう?どちらかが間違っているのでしょうか?
個人的にはそうでもない気がします.
  • firefox・operaは仕様書に記述があるので,文字列と言えどもtransform属性を有効化していました.
  • chromeではtext要素内部ではa要素とtspan要素とは役割的な相似が認められることからtransform属性を無効化していました.
どちらでも筋は通ります.つまりw3cの仕様にこの使い方に対する記述が無いから発生しているものと考えられます.ちなみにこのような問題は現在策定中のsvg2でも議論されているようです.従って将来的にどっちに転ぶか全く判りません.

結論


よって,text要素内部のa要素にはtransform属性を適用するのは危険.

0 件のコメント:

コメントを投稿