svgではテキストをグラフィックの構成要素として扱うことができる.本項では基本となるtext要素とそれに関わる要素群について示す.svgが文書形式としての役割を果たす上で,その中心となる要素である.
svgではテキストをグラフィックの構成要素として扱うことができる.本項では基本となるtext要素とそれに関わる要素群について示す.svgが文書形式としての役割を果たす上で,その中心となる要素である.
svgはhtmlと同様に文字列を挿入する機能を備えている.htmlにおけるspan要素に似ているが,1文字づつ表示位置・回転を調整することが出来る為,豊かな表現が可能となる.この機能はポスターや地図を構成する上で必須と呼べるものであるが,svgにおけるテキストはあくまでもグラフィックを構成する一部分として扱われるため,htmlや他の文書形式で有効となる禁則処理等の制御は一切行われず,全てのレイアウトの責任は実装者に委ねられている.従って文字列を文章として扱いたい場合は,htmlを使ってsvgグラフィックの上にhtml要素を重ねるとか,foreignObject要素を使ってhtml要素をsvgに埋め込むといった工夫が必要となる.
なおテキストの扱いについてはブラウザ間の動作がかなりバラバラなので,できる事ならあまり凝った事をせずに済ませたい.面倒ではあるが,1文字づつ配置する分にはどのブラウザでも目立った問題は起こりにくい.細かい属性の仕様はどちらかというと紙ベースの組版作業のためのものに見えるため,主にディスプレイでの表示を目的としたwebブラウザでは実装の優先順位が低いのかもしれない.
text要素はグラフィック内のテキストを表す.文字の描画は他の図形と同じくfill,stroke属性にて行う.描画位置の指定はx属性y属性で行う.テキストの描画は文字の下部を基準に行われるため,y座標の指定を適切に行わないと文字が描画されないことがある.(厳密にはこの限りではないが,日本語環境上ではこのように憶えておいて差し支えない.)また改行文字やタブ文字等は空白文字として扱われるため,改行を表現するには描画位置を指定し直す必要がある.
tspan要素はtext要素内の文字列の一部を表す.文字列の一部に異なるスタイルを指定したい場合に用いる.tspan要素を入れ子とすることもできる.
tref要素はsvg文書内部の文字列情報を参照して文字列の一部とするもので,text要素の他,title要素やdesc要素などを参照することが出来る.それ以外の動作はtspan要素と同等である.但し,SVG2で廃止となったため,WEBブラウザ環境では利用できない.
なおフォント設定等のテキスト描画に関わる属性以外の属性(例えばtransformやfilter等)の中にはtext要素でのみ有効なものが含まれている.そのため,文字列の一部に(反転等の)特殊効果を与えたい場合,htmlにおけるspan要素のようには行かず,面倒ではあるがtext要素を複数個に分割する,もしくはスクリプトを利用するなどの工夫を施す必要がある.
tref要素が参照する要素には制限がなく,参照した図形要素内部に含まれている文字列全てが出力される.この動作により,図形毎に定義されたtitle要素やdesc要素の内容をディスプレイに表示させるといったことが出来る.なお,tref要素から他のtref要素が参照している内容を取得するといったことは出来ない.
またインラインsvgの場合は親文書の内容を参照することも出来る.例えば「豪雪」をsvgから参照してみよう.
なおtref要素はSVG2で削除された.おそらくセキュリティ・アクセシビリティの観点から問題があると判断されたのだろう.
text要素の文字の描画位置に関わる属性は,何れもカンマ区切りのリストとすることで1文字ごとの描画位置を指定することができる.例えばx属性をリストとすることで,通常文字の幅で自動的に行われる文字送りを無視し,自由な位置に文字を配置することができるようになる.
dx,dy属性を用いると本来文字が描画されるべき位置からの差分値を指定することができる.通常x,y属性では2文字目以降の位置を絶対位置として記述する必要があるが,これらの属性を指定することで相対位置での指定が可能となる.
rotate属性を用いると文字を回転させることができる.回転の中心はグリフ定義の原点(概ね文字の左下近辺)となる.
text要素にtspan要素を挿入し,その中でx,y,dx,dy,rotate属性を指定した場合は元のtext要素の設定値を上書きしたような結果となる.従って下記のように文字列の一部のみの位置を変更しようとすると,後続の文字列にまで描画位置が適用されてしまう.面倒ではあるが,位置の指定はtext要素で一括して行うほうが良い.なお残念ながらtransform属性はtspan要素には定義されていないため利用することは出来ない.
text要素における文字位置は元々の仕様が非常にややこしく,複雑な指定を行った際にブラウザごとの動作の差として現れてしまうようだ.従って次の点に注意すると良いだろう.
html5文書において埋め込みsvgを用いた場合は,「 (空白)」等のhtmlにおける文字の実体参照を利用することができる.しかし,svgそのものや,xhtml5を使っている場合はxmlのエスケープに関わるもの「&(&),<(<),>(>),&apos(');,"(")」を除いてエラーとなってしまう.従って,数値を用いた参照「 」に置き換えるか,適宜!DOCTYPE宣言部において独自にdtdによる実体を定義するようにする.詳しくはxmlの仕様を参照のこと.
以下にtext要素のフォントスタイルに関わる属性を示す.これらはsvgのプレゼンテーション属性として定義されているため,text要素の属性として記述することが可能である
font-weight属性の動作例を示す.なお,この属性が正しく動作するにはフォント側で対応するグリフをサポートしている必要がある.一般的なフォントではnormal(400)及びbold(700)に相当するグリフのみをサポートすることが多く,それ以外の100や200と言った値は必ずしも期待通りの結果とはならない.
また値bolder及びlighterは現在のfont-weight値を基準に文字を相対的に太く/細くする事を表す.従って下記のようにtspan要素等で利用することとなるだろう.
文字列に関わる要素についてはxml:lang属性に言語・国名コード(例えば日本語であれば「ja-jp」)を設定することで日本語による文字列であることを明示することが出来る.この属性は単体で用いるよりも,セレクタの:lang擬似クラスと組み合わせることでsvg文書の国際化に役に立つものと考えられる.
文字間の間隔を制御するための属性として,kerning,letter-spacing,word-spacingが提供されている.
文字列全体の幅を指定することもできる.
text要素に設定した座標を基準にテキストが描画されるが,テキスト列のどこを基準に文字列を配置するかをtext-anchor属性で指定する.
テキストの縦書きを行う場合はちょっと面倒で,1文字づつ位置を調整する必要がある.その際,text-anchorをmiddleにすると見栄えが良い.ブラウザによってはwriting-mode属性をtbに設定することで簡単にテキストを縦書きにすることができる.なおカッコ"「」"や句読点などの縦書きと横書きで位置が変わる文字については調整が必要となる.
更にこの場合,幅の狭い文字(≒半角文字)については90度回転されてしまう.この動作はglyph-orientation-vertical属性で制御することができる.
direction属性では文字列の方向を指定する.これはアラビア語等の文字列の方向が右から左,左から右が混在する環境を考慮したものだが,日本語環境でもunicode-bidi属性をbidi-overrideとすることで強制的に右から左に文字を配置することができる.但しブラウザによって動作がバラバラなので利用は限定的である.
現状text要素にwidth要素を指定しても何も起こらないが,将来的にこの属性と他の属性と組み合わせることで文字列の自動処理が行われるようになる.
代表的なものとしてcss3で定義されたtext-overflow属性があり,文字列の描画幅がwidth値を超過した際に自動的に文字列が省略されるようになる.現状operaでのみ動作を確認することができるが,svgではその意味合いが曖昧な部分も多く,積極的に利用する状況にはない点に注意しよう.(textWidth属性等との意味付けも曖昧)
文字を配置する際の基準となる線を基底線(baseline)と呼ぶ.例えば日本語などにおいては文字の下端を揃えるように記述するため,基底線は下端であるし,アルファベットであれば大文字の下端が基底線であり,「j」「y」等の小文字はそこから下に一寸はみ出ることとなる.この基底線は言語毎に違い,異なる言語からなるテキストを扱うためにフォントには複数の基底線が定義されている.更にこの基底線はフォントの種類やフォントの大きさによって変化するため,文字列の整列度合いを制御するための機能が定義されている.
dominant-baselineは文字の描画の基準点(例えばtext要素のx属性,y属性)にどの基底線を合わせるかを指定する.alignment-baselineは文字を親要素のどの基底線に沿って並べるかを指定する.baseline-shift属性は基底線に対するオフセット値を指定する.
これらの属性はブラウザ毎の実装がまちまちで,いまいち使いにくい.これはw3cによる仕様自体が何を言っているのか判らないのが原因なので,今後も使えないものと考えたほうが良いかもしれない.chromeでの動作が比較的良いように見えるが,この動作も正しいものなのか判らない.
以上はsvgの仕様として記述されているものだが,この他にも環境によっては「CSS Text Module Level 3」等のcss3におけるスタイルが有効となる. 但し,これらはsvg側に対応するプレゼンテーション属性が存在しないため,専らstyle要素もしくはstyle属性にて指定する.
以下に代表的なものについて示す.
※但し,これらの動作はブラウザの実装に大きく依存するため,導入は慎重に行なって下さい.
空白文字(スペース,改行文字,タブ文字)等の扱いを制御する.設定によってはsvgコードに含まれる改行をそのまま出力することが可能だ.
1行の高さを指定する.white-space等の(自動/手動)改行設定を組み合わせる.
text要素の出力に改行が含まれている場合は:first-line擬似要素を適用することもできる.
同様にtext要素に対して::first-letter擬似要素が有効となる.
アルファベットの大文字・小文字を変換する.font-variantと混同しやすいが全く別の機能.
文字列に影を付ける.svg1.1の本来の仕様であればuse要素を使ったりfilterを掛ける必要がある.
SVGにおけるテキストに背景色を挿入するには,背景に相当する描画オブジェクトを配置する.なおCSSのbackground-colorプロパティはSVGにおいては無効である.
テキストの描画範囲は一般に環境毎に異なるので,背景色の挿入範囲を正確に求める為にjavascriptを用いる.下の例ではbboxメソッドを使ってテキスト全体の描画範囲を求め,その内容を元に背景となるrect要素を生成している.
document.addEventListener("DOMContentLoaded", function(){
var text = document.querySelector("#target");
var bbox = text.getBBox();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.x.baseVal.value = bbox.x;
rect.y.baseVal.value = bbox.y;
rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.style.fill = "yellow";
text.parentNode.insertBefore(rect, text);
}, false);
なお,テキストの一部に背景を付けたい場合はSVGTextContentElementインターフェースを用いると良い.詳しくはスクリプティングの項で述べる.
textPath要素を用いると予め定義しておいた曲線の上に文字列を配置することが出来る.文字描画の基底線が曲線に接するように配置される.(chromeでは不具合が出るケースがある.)
テキストの幅はパス上の長さで計算されるため,文字間の間隔が広がって見えたり詰まって見えてしまうのは致し方ない.
dominant-baseline属性で文字描画の基底線を変更することで,pathの真上にテキストを配置することもできる.firefoxで確認できる.
method属性ではパスに沿って文字列を並べるだけでなく,文字そのものを変形するかどうかを指定する.operaのみで動作.
textPath要素では通常パスの道のりを使って文字を配置していくが,その際に文字の幅を用いるか文字間隔を調整するかをspacing属性で指定する事が出来る.但し目に見えた違いは得られなかった.
参照しているpathがm操作によって千切れていた場合,テキストは自動的に分割され配置される.テキストの内容の方が長い場合,はみ出したテキストは省略される.この挙動を応用すると(path定義が面倒ではあるが)任意の図形を埋め尽くすようなテキストのレイアウトを実現することができる.その一方でhtmlにおける折り返し制御や禁則処理は一切行われないため,文章としての見た目は悪い.あくまでデザイン上の手間を省く手段として考えよう.
※どうしてもsvgに文章を埋め込みたいと言った場合は,foreignObject要素を使ってhtml要素(例えばdiv要素)を埋め込んでしまうという方法もある.
※本項ではSVG2で廃止された要素について解説しています.
グリフとは文字に対する文字の形を表す概念である.altGlyph要素は文書内の文字列について,本来描画されるべきグリフの代わりに別の見た目を持たせるための要素である.この要素を用いることで異体字や合字(リガチャ)等を元の文字データを損なうこと無く表示することが可能となる.例えば「高橋」と「髙(はしごだか)橋」と言った文字列をそのまま表した場合,これらは別々のデータとなるため,場合により非常に面倒なこととなる.これをaltGlyph要素を用いて見た目だけ「髙橋」とすることで,データの抽出処理において「高橋」のデータの全てを得ることが出来る.従って,デザイン的な目的よりもsvgをxml文書として扱いたい場合に有効な要素と言える.(なお,異体字に関わる問題はこちら・異体字セレクタに詳しい.altGlhpy要素の意義はこの異体字セレクタ問題を解決する所にあると思われる)
altGlyph要素はその役割上text要素の子として用いられるが,文字の見た目が変化する以外は機能的にtref要素と同様である.実際,代替グリフの情報が得られなかった場合はtref要素と同等の動作を採ることとなっている.
但し,このようなユースケースは欧米では一般的ではないためか,ブラウザでの実装状況は芳しくない(presto/旧operaで一部動作するのみ).
altGlyph要素の使い方には次の2つのパターンが存在する.
altGlyph要素から直接代替グリフを参照する方法で,svgフォントの機能としてのglyph要素を直接参照するケースと,グリフの識別子から定まるグリフを参照するケースの二つの方法に分けられる(こちらの方法によるグリフの置き換え方法の詳細は不明).この方法ではテキスト範囲が単一のグリフに置き換えられる.
なお,glyph要素は単体では存在できないため,必ずsvgフォントとして正しい形式で埋め込む必要がある.
文字列に複数のグリフからなる見た目を与える場合に利用する.atlGlyphDef要素で代替グリフの参照を表すglyphRef要素のリスト定義し,これをatlGlyph要素から参照することで複数のグリフからなる見た目を与える事が出来る.glyphRef要素に設定可能な属性はaltGlyph要素と同じである.
フォントなどの環境によっては特定の代替グリフが取得できないケースも考えられるため,代替グリフの候補セットをaltGlyphItem要素として定義することが出来る.glyphRef子要素の全てにおいてグリフの特定が出来たもののうち,最も先頭のものが代替グリフとして描画される.
グラフィックの描画を主眼に置いているSVGでは,いかなる環境においても同じ見た目となることが求められる.一般に文字列をスクリーンに描画するにはシステムにインストールされているフォントファイルを介し文字の形(グリフ)を取得する.しかし利用可能なフォントの種類は環境によりまちまちであり,必ずしも同じ見た目とはならない.そこでWEBブラウザは近年インターネット上のフォントファイルを自動的にダウンロードする仕組み(WEBフォント)を採用している.この仕組みを用いれば環境に依らない常に同じグラフィックが得られることになる.
下に実際にWEBフォントを利用した例を示す.googe web fontsが公開しているWEBフォントの利用をstyle要素で宣言し,それをtext要素から参照している.
WEBフォントの呼び出し方はHTMLでの方法と全く同じである.なおスタンドアロンのSVGファイルからWEBフォントを利用する場合は,SVGにはHTMLのlink要素に相当するものがないため,xml-stylesheet処理命令に描き直すかlink要素が参照している内容をstyle要素に貼り付ける必要がある.
指定された内容
<link href='http://fonts.googleapis.com/css?family=Chela+One' rel='stylesheet' type='text/css'>
(1)これをxml-stylesheet処理命令に書き換えて,svg要素の前に追加する.
<?xml-stylesheet href="http://fonts.googleapis.com/css?family=Chela+One" type="text/css"?>
(2)link要素が参照している「http://fonts.googleapis.com/css?family=Chela+One」の内容を開くと次のような内容である
@font-face {
font-family: 'Chela One';
font-style: normal;
font-weight: 400;
src: local('Chela One'), local('ChelaOne-Regular'), url(http://themes.googleusercontent.com/static/fonts/chelaone/v1/DHUBEAsCcSRMyWTJ6sisfj8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
}
この内容をstyle要素に書き込む.
WEBフォントが利用できないのであれば,予めグリフをパスに変換してしまう(フォントのアウトライン化)方法もある.大抵のドローイングツールには文字列をパスに変換する機能があるためこれを利用する.なお元々のテキストデータはpath要素に変換される過程で失われてしまうので,title要素やdesc要素を用いて補っておくと良い.この場合,レイアウトが保証される一方で文字列の選択が出来ない等のアクセシビリティの損失が発生する.
なお,「アウトライン化したフォント」の「WEB環境における公開/配布」が可能かどうかは当該フォントのライセンス条項に照らしあわせて適切に判断せねばならない.ラスタ形式の画像と異なり,理論上はSVGに埋め込まれた「アウトライン化したフォント」データを二次利用することも可能だからだ.