第二回部会 - Part 3

概要:
CSS3 Writing Modesの研究 - Part 3
関連するW3C仕様:

BPS株式会社CSS部の第二回部会のPart 3です。 CSS 3のWriting Modesについてお送りしています。 Part 1では概要をお伝えし、Part 2、Part 3が本編となっております。

なお、この発表は2014年3月20日のCandidate Recommendationに沿って行われています。 書き起し時点で最新仕様を確認し、異なる部分があればその旨記載にするするように努めています。

インラインの進行方向

行の中で、どのように文字が進むか見ていきましょう。

inline-direction

上の図で、様々な文字が行に沿って並べられています。 日本語は、横書きでは左から右、縦書きでは上から下。 アラビア語は、横書きで右から左に進んでいます。 これが、インラインの進行方向です。

方向としては4方向に見えますが、実は2方向で足ります。 英語の「Hello, world.」のサンプルは、縦書きの中に英語が入っていて、上から下に進んでいます。 縦に進むか横に進むかはwriting-modeプロパティですでに決めてあるので、残る特性として、行に対して文字がどのように進んでいるかに注目します。 英語の字の天が向いている方向に頭を傾けて見ると、左から右に進んでいるように見えます。 この方向をインラインの進行方向と見ます。

文書やブロックの中の主要なインライン方向のことを、"inline base direction"と呼びます。 仕様ではこのようになっています。

The inline base direction is the primary direction in which content is ordered on a line and defines on which sides the “start” and “end” of a line are.

(インライン基本方向とは、コンテンツが行内で進行する主要な方向で、行のどちらが「開始点」「終了点」かを規定する。)

インラインの進行方向を決める要素

さて、ここでクイズです。 インラインの進行方向を決める要素は、何だと思いますか? 下記のどれが該当するでしょう。

  • CSSのプロパティ
  • フォント
  • HTML
  • Unicodeの仕様
  • Unicodeの制御文字

CSSのプロパティが影響しそうな気がしますよね。 そう思った方。 ひとまず正解です。 他に何が影響するでしょうか。

フォント

フォントを変えると、それだけで突然左から右になったりするでしょうか? いいえ、実はフォントの中にはそういう情報が入っていません。 例えば、RTLに対応していないテキストエディタでアラビア語を表示すると、文字の進行方向は右から左になるけど、単語の配置の進行方向は左から右のままになります。 アラビア語のフォントを使ったことある人がいれば、体験しているでしょう。

まず、下図が正しい表記です。おなじみの「アッサラーム・アレイクム」という挨拶の言葉を、Chromeで描画しました。

arabic chrome

CotEditorでは正常に表示され、カーソルの動きも正しいです。 改行位置を示す、薄い色のパラグラフマークが、行頭にあっておかしいように見えますが、これは正しいです。 アラビア語の行末は左ですから。 本当は左の欄外にパラグラフマークを置いてほしいですが。

arabic cot

viは、ターミナル版でもMacVimでも、すべての文字が英字のように扱われて、左から1字ずつ置かれるようです。

arabic macvim arabic vim

Wordは期待していましたが、うまく筆記体の線がつながりません。 また、単語ごとに左から配置されるようです。 先ほど言った、単語の配置の進行方向は左から右のままになる例です。 本来はすべての単語を右から配置し、単語内の文字もディスクに記録されている順とは逆で右から左に配置してほしいところです。 アラビア語対応のWordはありますので、筆者の環境のせいと思われます。 条件が良好ならば、上のChromeの描画のようになります。

arabic msword

HTML

HTMLで進行方向に影響するものとしてわかりやすいのが、<bdo>タグです。

1
2
<bdo dir="ltr">السلام عليكم and Hello</bdo>
<bdo dir="rtl">السلم عليكم وHello</bdo>

arabic cot

上のように、文字列をbdoタグで囲って方向指定すると、その中の文字に「強いBIDI属性」が付きます。 例えば、Aでは、英語の文字列は通常は「LTR」の弱い属性を持っていますが、それが「強いLTR」で上書きされます。 LTRにLTRを上書きしても、効果はありませんが。 効果があるのが、その隣にあるアラビア語の部分です。 アラビア語はデフォルトで「RTL」の属性を持っていますが、それがbdoタグの方向指定により「LTR」に上書きされます。 すると、アラビア語であるにもかわらず、文字が左から右に流れるようになります。当然、正しい単語としては認識できなくなります。 Bの例のほうがわかりやすいですね。 「Hello」という英語部分が「olleH」のように逆向きに記されて、何の単語かよくわからなくなっています。 bdoによってRTLに上書きされたからですね。

これは、本来RTLでない言語をRTLのように表示する、などの用途に使います。 日本語で試してみましょう。 日本語は本来RTLではないので良い例にできます。

1
<bdo dir="rtl">カステラ</bdo>

このようにマークアップすると、右から左に流れる、車や屋台の側面の看板のようになります。

kasutera

余談

下の写真は、1938年(昭和13年)ころの、大阪の天王寺駅の様子だそうです。

Tennoji station

戦前ですが、左から右に進む横書きの看板が多くあることがわかります。 右上にある「阪和食堂」のみが右横書きで、ほかは左横書きのようですね。 新聞の見出しでは、読売報知新聞が1946年1月1日から左横書きに変更していて、ほかの新聞もそれに続いています。 確かに戦後の国語教育で、左横書きが基本とされていますが、それ以前も左から右の横書きは珍しくなかったようです。

HTML(続き)

余談を挟みましたが、本文に戻ります。 ほかにHTMLで影響するもの……<bdi>タグです。

1
Arabic word <bdi>السلام عليكم</bdi> (1): "Hello" (1) in English.

<bdi>タグは、タグの中に入れた文字のBIDIプロパティが、タグの外の要素に影響しないように隔離するためのタグです。 CGIで使うとよいでしょう。 CGIが、テキスト要素として外国語の可能性のある文字列を書き出すところで、予めその要素を<bdi>タグで囲っておきます。 そうすると、たまたまそこにアラビア語の単語が書き出されたとき、タグの外にある要素にアラビア語の語順が波及して適用されるのを防ぎます。

arabic cot

Aが、括弧付きの数字が崩れてしまう例です。 bdiタグを使用しないせいで、「(1)」とひとまとまりになっていてほしいところで、括弧や数字が分かれてしまっています。 なぜこうなるかというと、数字、括弧、記号などは、アラビア語の中でも使われ、これらのBIDI属性は中立だからです。 中立のものは、アラビア語のコンテキストではアラビア語の数字や記号、英語のコンテキストでは英語の数字や記号、として解釈されます。 括弧の直前にアラビア文字があると、アラビア語のコンテキストと誤って解釈され、意図しない並び順になってしまいます。 それを防ぐために、isolateを行います。

Bではbdiタグで囲い、アラビア語が入る可能性のある部分を本文と分離しています。 数字部分にまでアラビア語の方向が波及せずに、「(1)」がひとかたまりになっているのがわかります。 正しくisolateされていますね。

ほかにHTMLで影響するものに、<p dir=“rtl”>があります。

1
2
<p dir="ltr">السلام عليكم and Hello</p>
<p dir="rtl">السلم عليكم وHello</p>

arabic cot

Aは、文全体としては英語で書かてていて、「アッサラームとHello」のようなことが英語で表現されています。 リストマーカーの「A」自身も左に置きました。 英語が基軸ですから、文の中身も、左から右に流れます。

Bは、アラビア語の文章です。「and」のかわりにアラビア語の単語「و」を置き、「アッサラームとHello」をアラビア語で言っています。 ちなみに、アラビア語は基本的にスペースで分かち書きをしますが、「و」はスペースを後置する必要のない単語です。 文章全体としては、アラビア語の文ですので、右から左に流れます。 リストマーカーの「B」も、アラビア語に従って、右に置きました。

このように、dirを指定することで、文章が全体的にlrtなのか、rtlなのかを指示することができ、文章全体のレイアウトが変わります。

Unicodeの仕様

これも影響があります。 各言語の仕様で、その言語は左から右に進む、などと決まっています。 例えば、アラビア文字は右から左に進む、と決まっていて、ブラウザがHTMLからアラビア文字を見つけて、Unicodeの仕様通りに「右から左に進む」ような文字として扱います。

これは文章全体や段落全体の話ではなくて、単語がどう記述されるかです。 たとえば、「السلم عليكم」のディスク上での記録順は、前述したVimの例のように「ア」「ッ」「サ」「ラ」のようにアラビア語を発音する順序です。 Vimの例を再掲します。

arabic macvim

Vimでは残念ながらディスクに記録されている順に、左から文字が表示されていますので、格好の例になります。 上のような順で左から文字を読み込み、Unicodeの仕様に照らす、というわけです。

文字をいくつか読み、rtl属性の文字の連続ならば、アラビア語の単語のように右から左に流れる塊として描画します。 Cotエディタのように右から左に再配置すると、正しい描画が完成となります。

arabic cot

正解画像と比較してみてください。

arabic chrome

Unicodeの制御文字

Unicodeの文字自体にある属性の他に、UnicodeにはBIDI用の制御文字があります。 任意のテキストを部分的にRTLにする、などのことができます。 仕様の詳細は、UTR9にまとめられています。

定義されている文字は、上で説明した、HTMLタグによるマークアップと同じ機能のものが揃っています。 UTR9の「2.7 Markup and Formatting Characters」にその対応表があります。

例えば、デフォルトがLTRの日本語をRTLにオーバーライドするときは、U+202E RIGHT-TO-LEFT OVERRIDEを使います。 閉じタグに対応するのはU+202C POP DIRECTIONAL FORMATTINGで、RTLにしたい日本語の直後に置きます。 マークアップではなくUnicodeの文字なので、OSやエディタが対応していれば、プレーンテキストでも消失することなく使えます。

RTLの属性を周囲に伝搬させないためのbdiタグには、U+2067 RIGHT‑TO‑LEFT ISOLATEなどが対応します。 bdiの閉じタグに相当するのは、U+2069 POP DIRECTIONAL ISOLATEです。

というわけで、クイズの答えは、フォント以外に挙げたものが正解でした。

余談

かつて、Windowsのファイル名を使ったいたずらの手法として、BIDI制御文字を利用して、拡張子を隠すのがありましたね。 .txtと書いてあるように見えるのに、実は.exeだったりします。 アラビア文字となる部分は右から左に進むので、隠したいところがファイル名の表示枠の中央に来るように、また、見せたいところが表示枠の右に来るように、制御文字を入れていくわけです。 右端に「.txt」と見えていても、それは表示枠の中でたまたま右端に見えている文字列で、本当の拡張子は制御文字によって左に逃がされている「.exe」のほう、というわけです。 「.txt」に見えるため安全だと思ってダブルクリックで開いてしまうと、本来の「.exe」として実行されてしまうわけです。

bidiname

Unicodeの仕様を悪用してイタズラに使うというのは、けしからんことです。 正規の仕様として生きていますので、外から持ってきたファイルを扱うときは注意が必要ですし、正しい使い方をしてほしいものです。

CSSのプロパティ

インライン方向に影響のある要素をいくつか見てきました。 今回の目玉である、CSSのプロパティを見ていきます。 仕様はこのようになっています。

The direction property specifies the inline base direction of a box and, together with the unicode-bidi property and the inherent directionality of any text content, determines the ordering of inline-level content within a line.

(directionプロパティは、ボックスのインライン基本方向を指定し、unicode-bidiプロパティおよび継承している テキストコンテンツの方向性と組み合わせて、行内のインラインレベルのコンテンツの順序を決める。)

direction プロパティ

まず1つめのプロパティ、directionです。 値は下記の2つが指定できます。

  • ltr
  • rtl

ltrは、左から右に進む。英語や、日本語の横書きなど。行の左がstart、右がendになります。

rtlは、右から左に進む。アラビア語などです。英語などとは反対に、行の右がstart、左がendになります。

このプロパティを指定するだけで、各文字がその通りに進むかどうかは、また別です。

ブロック内のある言語の文字列は、そう簡単には崩れません。自然に読むことができる並びのままになります。 例えば、英語の文字列ならば、単語の塊は崩れないし、単語同士の並びがおかしくなることはありません。 文全体の並びは至って普通です。

英語の中に、アラビア語など進行方向が異なる文字が入ると、話が違ってきます。 英語とアラビア語は、それぞれの連続の部分では自然に読める順で並びますが、境界のところで並び換えが起きます。 また、画像などのインラインブロックが入った場合も、そこを境界として、並び替えが起こります。

unicode-bidi プロパティ

どうしても各文字の順序を制御したいときは、unicode-bidiプロパティも合わせて変更します。

bidi-override:

This value puts the box’s immediate inline content in a directional override.

For an inline, this means that the box acts like a directional embedding in the bidirectional algorithm, except that reordering within it is strictly in sequence according to the direction property; the implicit part of the bidirectional algorithm is ignored.

(bidi-override: この値は、ボックス直下のインラインコンテンツのdirectionをオーバーライドさせる。 インライン要素においては、BIDIアルゴリズムの進行方向の埋め込みがあったようにボックスが動作する。 ただし、その中での文字の並び換えはdirectionプロパティに従って厳密に行われる。 BIDIアルゴリズムで暗黙に行われているものは無視する。)

unicode-bidi: bidi-overrideなどの指定をすることにより、各文字の順序を指定することができます。 プロパティには下記の値を指定できます。

  • normal
  • embed
  • isolate
  • bidi-override
  • isolate-override
  • plaintext

日本人なので、bidi関連は軽く触れるだけで終わりにします。 各値の意味は、仕様書を参照してください。 概念はHTMLタグとUnicodeの制御文字で説明していますので、値の名前から予想ができるかと思います。

興味のある方がいたらCSS研究部でも詳しく取り上げてみますが、今回はこれくらいにして次に移ります。 縦書きにあまり興味を示さない大半の欧米人の気持ちと同じかもしれません。

余談

せっかくなので、余談コーナーにてBIDIのアルゴリズムの簡単な解説をしてみます。

BIDI用語を簡単に説明します。

暗黙の方向

Unicode、各文字はデフォルトのBIDI属性が決められています。 例えば、アラビア文字は、各文字が右から左に積まれるのがデフォルトです。 アラビア語の中で使われる算用数字は、これがアラビア語が「双方向(BIDI)」に分類される所以なのですが、アラビア語中であっても左から右に進みます。 こうしたデフォルトの動作による文字の並び換えが、「暗黙」と言われているものです。

埋め込みレベル

用語の説明をしたところで、アルゴリズムをいくつか例示しながら説明してみます。

BIDIアルゴリズムにおいて、ある文字列がどちらに進むかは、整数を使って管理されています。 偶数(0を含む)のレベルは左から右、奇数のレベルは右から左です。 文字列のあるところから、逆方向の文字を挿入したいときは、その開始点でレベルを1つ上げ、その終了点でレベルを1つ下げます。

レベルを上げるための号令が、UnicodeならRLIやRLO文字であり、HTMLであればbdiタグやbdoタグ、というわけです。 下げるのはUnicodeのPDFやPDI、HTMLの閉じタグに当たります。

UTR9の例を見てみましょう。 この例では、下記の記法で、ASCII文字だけで説明されています。

  • 小文字は英語の成分
  • 大文字はアラビア語の成分
  • LRIは「>」の制御文字
  • RLIは「<」の制御文字
  • 閉じタグは「=」の制御文字

example 1

Example 1は、制御文字はなく、暗黙の属性の処理の例となっています。 全体としては英語の文になっています(最初の“means"という英語の動詞が、小文字で書かれていることから)。 ディスクに記録されている順序(「Storage」の行)を読んでいくと、最初のほうは小文字なので英語の成分が並んでいるようです。 大文字は「アラビア語」を示しますので、右から左の字として読んでいきます。 英語は偶数、アラビア語は奇数で方向を管理しますので、読みながら対応する0と1を入れていきます(「Resolved Levels」の行)。 1が立っているところはアラビア語の順序で処理したものとして、右から左に進みます。 「RAC」に見えますが、アラビア語のアルファベットを模擬して右から「C」「A」「R」が並んでいることを示しています。 結果として、英語の文に入っているアラビア語の単語が、きちんと右から左に描画されることを示している例になります。

example 1

Example 2は、まず文頭のRLI記号(「Storage」の行で「<」と表示してある)から、全体としてはアラビア語の文になります。 動詞「means」が大文字で書いてあるので、アラビア語で何かを説明しているということですね。 小文字は英語成分で、「car」になっています。 英語成分は、アラビア語の文の中では「左から右」の成分が混じっているものとされるので、レベルを示す整数は次の偶数「2」にします。 英語成分の終わりで、アラビア語の成分に戻りますので、レベルを下げて奇数の「1」にします。 さて、全体的にはアラビア語の文ですから、右から左に描画します。 小文字の「car」をまず右端に、「2」つまり左から右への成分として配置し、そのあと(左です!)に「1」つまり右から左の成分を続けていきます(左方向に続けます)。

そうして、アラビア語の説明文「スマシメシ ヲマルク ハcar」が完成します。

example 1

Example 3では、レベルが入れ子になっていますね。 英文の中にアラビア語のセリフが入り、しかもその中に英単語が使われている、という体裁です。 Example 1および2が組み合わされたものとなっています。 各自で読み解いてみてください。

少し解説すると、全体としては英語の文章で、セリフの中はアラビア語がベース言語です。 セリフの外側にある引用符や句読点は、英語の文に属します。 中のアラビア語の語順が、外の英語の記号の順序に影響しないよう、isolateする制御記号が入っています。

directionの影響を受けるもの

本文に戻ります。 directionを指定すると、こういうものが影響を受けます。

  • テキストの向き
  • text-alignの初期値
  • text-indent
  • テーブルの向きも変わる

テキストの向きは、当然、変わりますね。 上で述べたように、インライン内の同じ言語の塊は変わりませんが、インラインボックスの末端を境にして並び換えられます。

text-alignの初期値も変わります。 段落全体を行の左右どちらに寄せておくか、というのがtext-alignです。 普通の文章は行頭方向に揃えるのが自然ですので、英語の文章では左寄せとしてtext-align: leftが指定されると自然です。 アラビア語も同様に、同じ「行頭方向」が自然ですが、物理的にはそれは「右」を指します。 よってtext-align: rightが指定されればいいことになります。 こうなるように、初期値がleftとrightで変わります。

direction

同様に、インデントも変わります。 LTRのときは最初の文字を右に向かって追い出すようにインデントを入れ、RTLは最初の文字を左に向かって追い出します。

テーブルの向きも変わります。 横書きの中では、下のように、directionを切り替えるとテーブルのセルが進む方向が変わります。

table-h

縦書きの中でも同様です。

table-v

上の図で、テーブルの行は縦に走っていますね。 「Col.1」「Col.2」「Col.3」と書いてあるセルのことです。 ちょうど横書きの表を90度回転させた形で、ltrのときとrtlのとき、2通りの方向があります。

directionを切り替えると、このように、テキストを寄せる方向や、テーブル内のセルが積まれる方向が変わります。

余談

出版社のEPUBコンテンツでも、表はよくあります。 EPUBもHTMLとCSSを利用したコンテンツで、特定バージョンのHTML/CSSを参照するように規格化されています。 CSSは使用実績があるものを仕様化していくので、様々なWebコンテンツが先取りして実績を積み重ねてもらうのは大変結構なことです。 しかし、ブラウザ実装が追い付いていないのに、商用のコンテンツで縦書きの表を使うのは、ちょっと恐ろしいことかもしれません。

行の向きと文字の向き

あと2つ要素があります。 下の図にある、「行の向き」「文字の向き」です。

orientation

  • 行の向き (line-orientation)

図の赤い矢印です。 "Line Top"が示す方向が、行の天の方向です。 line-orientationによって、line-top、line-bottom、line-over、line-underが指す方向が決まります。

日本語で強調するときに引く傍線は、line-overの位置、つまり右に置かれます。 行の進行方向は右から左ですから、行に対して天のほうに引かれるわけです。 同じ縦書きのモンゴル語でも、実は傍線は日本語と同じで、右に引かれます。 行の進行方向に対して地のほうになりますが、line-orientationに従ってline-overのほうに引けばよいことになります。

  • 文字の向き (text-orientation)

図の黒い矢印です。 行の向きは変わっていないのに、文字の向きは「Hello」と「世界」で違っていますね。 横書きは水平に進むので、文字の向きは1パターンが描画できればよいのですが、縦書きのときは、2パターンあります。

文字を分類

世界の文字をいくつかのカテゴリに分類してみましょう。 文字の向きに注目した分類を行うと、下記の3つに分かれます。

  • horizontal-only
  • bi-orientational
  • vertical-only

horizontal-onlyというのは、横書き専用の文字体系です。 ローマ字、キリル文字、アラビア文字、など横書きしか行わない体系です。 特にアラビア文字は、筆記体のように、筆画が隣の文字と続けて書く体系のため、縦に組み直すことができません。

横書き専用の体系を縦書きの中で文章にしたい場合は、文章全体を90度傾けた形で書きます。 この操作は"rotate"と言って、文字を回転させて、進行方向に沿って並べます。

rotate

bi-orientationalは日本語や中国語など、漢字を使用する体系が主に該当します。ハングルもこれに入ります。 接頭辞"bi"が示すように、2通りのorientationに対応している、という意味です。 縦書きでも横書きでも、文字は回転させずに、そのままの方向で積んでいくことができます。

この操作を"translate"といい、文字の回転は行わずに、位置だけを行に沿うように変更します。

translate

vertical-onlyは、例が少いですが、モンゴル文字のように上から下に書く体系です。 縦書きのときは、このままの方向でよいですが、横書きの中でモンゴル文字による文章を書くときは、全体を90度傾けた形にします。

これら3つのカテゴリがありますが、縦か横かの二分にする分け方もあります。

orientation

bi-orientationalを、縦と横に重複させて分類するやり方です。 horizontal script、vertical scriptに分けます。

何で決まるのか

rotateするか、translateするか、は何によって決まるでしょうか。 またクイズです。 先ほど出たのと同じリストですが、このうちのどれが、各文字の変換方法を決めるでしょう。

  • CSSのプロパティ
  • フォント
  • HTML
  • Unicodeの仕様
  • Unicodeの制御文字

正解は2つあります。 Unicodeの仕様と、CSSプロパティですね。

余談

CSS仕様ではrotateとtranslateだけが説明されていますが、本当にそれだけで良いでしょうか。

translateだけをした図が下記です。 縦書きで、小書きの「っ」の位置がちょっとおかしいのがわかるでしょうか。 少し左下に寄っていますね。

small-tsu-malposition

小書きの仮名や鉤括弧など、位置が不自然なものがそのままになってしまいます。 これらについても説明する必要があります。

プロパティ

CSSで向きを制御するのは、text-orientationプロパティです。

  • mixed
  • upright
  • sideways-right
  • sideways-left
  • sideways
  • use-glyph-orientation

があります。 下図にいくつかのサンプルを載せます。

text-orientation

mixed: 自然な感じです。たまたま日本語および日本語の句読点のみが使われる文では、uprightと変わりません。 mixedに英語、数字、記号などの外来の文字が入ると、90度回転して、字の天が右を向きます。

upright: 日本語も英語も、文字が正立します。 英字もほとんど縦で書かれます。 新聞などはuprightが大好きで、しかも全角で書くというスタイルが普及しています。

sideways: これはsideways-rightへのショートハンドです。

sideways-right: 日本語も英語も、文字の天を右にします。

sideways-left: 同様に、文字の天を左にします。 これだけが例外的で、アンダーラインの位置が変更され、右になります。 他の値では、アンダーラインの位置はすべて左です。

use-glyph-orientation: SVGで使っていましたが、不安定なので削除予定らしいです。

6つ書きましたが、実質は4つの意味です。

余談

ところで、概要でやったように日本語の縦書きで、「アンダーライン」というのは左側に付きます。 右側に付くのは「傍線」(overline)といいます。 傍線は、教科書などでよく見かける、強調部分の右に引く線のことです。

傍線を呼ぶときうっかり「アンダーライン」という単語を使ってしまいそうですが、それは逆側に引く線のことなので、注意が必要です。 日本語で右に付ける線を「下線を引く」とは言いませんので、これを思い出して、傍線を引く、と言うようにしましょう。

なお、CSSでは「傍線」への言い換えはややこしい気がしますが、CSSでは「傍線」のように右に付く線が示されていないので、仕方ないです。 右に来るのが「傍線」なので、縦書きで最も一般的な線は「傍線」と覚えましょう。

余談

sideways-leftの扱いは、W3Cのメーリングリストや国際会議の場で、揉めに揉めているホットな話題です。

sideways-rightもsideways-leftも、横書きにして全体を90度倒したような表記です。 horizontal-onlyな言語もbi-orientationalな言語も、字の天を左右どちらかにして、行全体が回転します。 しかし日本語の縦書きの中で、英語やアラビア語の成分だけをsideways-rightに描画するニーズはありますので、おそらくsideways-rightは必要なプロパティと考えて間違いなさそうです。

sideways-rightがあるなら仕様の対称性を満たしてleftも用意するのが当然という声もあります。 これも自然な意見なのですが、縦書きの中では使用例があまりなく、単に回転させるだけでよいのではないかという意見もあります。

日本人の立場からすると、使用例がわかっているsideways-rightのほうを仕様に載せて、CSS Writing Modes Level 3を「勧告」のステータスに持っていくのがよい気がします。 勧告になれば、世界中のブラウザがこの仕様で縦書き対応を進められ、Web制作のほうも安心して仕様化されたプロパティを使うことができます。 世の中に、縦書きコンテンツも広まることでしょう。

その間、どうしてもsideways-leftが必要ということであれば、次の更新(Writing Modes Level 4というのでしょうか)で仕様化するのがよいでしょう。

mixedの詳細

mixedのとき、文字の向きがどうなるか、詳細に見ていきましょう。 ざっと分類すると、日本語は正立、英語は回転でしたね。 しかし細かな記号などはどうでしょう。

symbols

矢印などは回転したほうがいいのか、そのままがいいのか、どちらでしょうか。 著者の意図によって変わるので一概に決められないでしょうか。

矢印は、回転します。 横書きのテキストエディタで「↑」(上向き矢印)を使って、「↑の文例では…」のように使うのを想定して、回転するわけです。 物理的に上を向いているわけではなくて、文の先の方を指している、のような記号と考えて、回転の対象になります。 ちなみに、Unicodeでの矢印の名称は、U2191 UPWARDS ARROWのように物理方向を指すような用語が付けられています。 回転するともはや「UPWARDS」ではなくなってしまうので、残念な名称です。

どの文字が回転し、どの文字が正立するかは、Unicodeの付属文書「UTR50」というもので定められています。 矢印が回転するのも、この文書の規定に従うためです。

UTR50

縦書きのときの文字調整は、

  • translate
  • rotate
  • 置換

の3つの操作があります。

UTR50では、Unicodeのそれぞれの文字が、縦書き時のこの3つの操作のどれを行うべき文字なのか、漏れなく指定しています。 このUnicodeプロパティを「VO」(Vertical_Orientation Property)と言い、U・R・Tu・Trいずれかの分類記号(クラス)となっています。

  • U: 日本語の文字はほとんどこれに該当する。Uprightの略で、回転しない。
  • R: 英字はほとんどがR。Rotateの略で、回転する。
  • Tu: 縦書きグリフがあればそれを使い、なければUprightになる。Translate or Uprightの略。
  • Tr: 縦書きグリフがあればそれを使い、なければRotateする。Translate or Rotateの略。

utr50

余談

UTR50は、Unicode Technical Report 50の略です。 Unicodeの規格周辺には、下記の3つの基準で補助的な文書が用意されています。

  • UAX: Unicode Standard Annexの略で、Unicodeの仕様の一部。ただし別ドキュメントとして提供されている。
  • UTS: Unicode Technical Standardの略で、Unicodeコンソーシアムが承認するものの、Unicode仕様からは独立して発行される情報で、Unicode仕様の一部ではない。
  • UTR: Unicode Technical Report。単なるテクニカルレポートで、Unicodeコンソーシアムが参考情報として出しているレポートであり、仕様の一部ではない。ただし、情報としての権威は決して弱いわけではない。

これらの基準すべてを含む形で通し番号が付けられています。 UTR50は、多少欠番があるのは無視するとして、UAX・UTS・UTRを合わせて数えた中の50番目の文書という意味合いです。

組文字

ここで面白い文字があります。 メートルやキログラムなどの組文字はどうしましょう。

vertical meter/kilogram

横書きではAの元のデザインだけあればよいですね。 問題は縦書きです。回転するか、真っ直ぐ立つか、は当然正立でよいです。 しかし正立といっても、Bの組み方とCの組み方で違いがあるのに気づくでしょうか。 Cは、横書きと同じデザインです。縦書きの中でこのデザインが使われると、読みにくい気がします。 縦書きなのに、組文字の中の世界だけ横書きになってしまう。

Bのほうが自然な感じがしますよね。 デザイナーがこういうふうにフォントグリフを作り、フォントの中に別グリフとして登録すると、Bのようになります。 縦書き用の代替グリフは、丁寧に制作してあるフォントならば、たいてい収録されています。 縦書きに対応を謳っているフォントならば、きちんと入っているはずです。 自主制作のフォントでは、入っていることは多くないかもしれません。 対応しているフォントなら、Microsoft Wordでも、縦書きのできる他のソフトでも、Bの形で見ることができます。

高価なフォントは、この対応が良いのです。 1つの太さにつき3万円ほどするフォントや、1書体で10万円以上もするフォントなどは、こうした文字がきちんと収録されています。 50書体で3000円のような格安のフォントでは、縦書き対応の文字収録には期待できなそうです。 値段の違いは、そうした対応状況に現れてきます。

縦書きグリフへの置換のほかに、縦書きメトリクスというのもあります。 「っ」のような小書きの文字など、変形するほどではなくて位置情報だけ差し替えたいようなときに使うプロパティです。 縦書き用のメトリクスが収録されているフォントを、対応するアプリケーションで使うと、縦書きのときにその情報を参照することによって、右に寄ります。

フォントファイルの中で、ある1字のことを「グリフ」と呼びます。 グリフのデータは、グリフの線画がちょうど収まるような四角形の中で、座標データとして収録されています。 その四角形を出る座標はありませんので、上下左右に寄せるというような情報は、枠内の位置調整ではなく、別のプロパティで与えられています。 アプリケーションのほうで箱の中に文字を描画するにあたり、どこを起点にしたらよいかという数値がフォントに入っていて、縦書き用と横書き用で分かれています。 位置情報を収録するテーブル名は、OpenTypeの規格上では「GPOS」と呼ばれている。 そこに、起点にすべき数値が収められています。

ちなみに、縦書きにすると、句読点が真ん中に寄ってしまうようなフォントがあります。 それは、縦書き用のposition情報がフォントに収録されていないか、アプリケーションのほうが縦書きメトリクスをフォントから読み取ってくれないか、のどちらかが起きていると考えられます。

余談

英単語の話題です。

さきほど別のスライドで出てきたTranslateは、並行移動の意味のTranslateです。 UTR50に出てくるTranslateは、そうではなく、置換の意味のTranslateです。 もしかしたら、Substituteのほうが適切な単語かもしれません。

置換は、英語ではSubstituteですね。

CSSでは2分類

UTR50では4種類のクラスになっていますが、なぜかCSSでは2種類の対応となります。 UTR50のU、Tu、Trの区別が、CSSでは統合されているからです。 この経緯は、メーリングリストで見つかります。

But how text layout is done with actual fonts on the web is really the domain of CSS, not of Unicode. For the very small number of ‘Tr’ codepoints that lack vertical alternates in fonts, it doesn’t make sense to have optional behavior since for a given piece of content only one behavior will be considered “correct” by an author.

(しかし、テキストが各フォントでどのように配置されるかはCSSの守備範囲であり、Unicodeの範疇ではない。 Trのコードポイントなのに縦書き代替指定を欠く少数の文字のために、オプショナルな挙動を決めるのは無駄である。 ある記述について、ページ制作者が「正しい」とする配置は1つだけなのだから。)

日本語対応のフォントであれば、Trのコードポイントには縦書きの代替グリフが入っていることが大いに期待できるため、無い場合のことは考える必要がないだろう、ということです。 というわけで、CSS Writing Modesの仕様を読むと、文字の向きは下記の2つの分類になっています。

  • Typeset Upright: 縦書きグリフや縦書きメトリクスがあればそれを使い、なければ正立。
  • Typeset Sideways: 常に横書きのグリフを使って、90度回転させる。

U, Tu, TrはCSS仕様ではTypeset Uprightと書いてあり、RはTyepset Sidewaysしようと書いてあります。 CSS仕様のほうがすっきりしているように見えますね。

しかし一筋縄でいかないところが、CSS仕様の怖いところです。 UとTuは普通に解釈してUnicodeの定義に一致するところは良さそうです。 Rも、常に回転ですから、Unicodeの仕様とCSSの仕様が合致します。 U・Tu・Rはこのように、同じ方向に向くようになっているので特に問題ないですね。

しかし、TrがUnicodeとCSSで解釈が異なるのが気になります。 Unicodeでは縦書きグリフがなければ回転、となっています。 一方、CSS仕様では縦書きグリフがあればそれを使い、なければ回転せずTypeset Uprightというわけで、回転しないのがデフォルトとして考えられています。 Trは、回転しないのが普通だけど、回転してもよい、という曖昧な書き方になっているのです。

実際に字を例にして見ていきましょう。 U+2016 Double Vertical Line が格好の例です。

double vertical line

VOはUで、正立として扱われます。 UTR50が出る前に、多くのフォント作者がこの字をデザインしたときに、回転させようということで収録してしまったため、混乱している文字です。 本来は縦書き時に正立してほしい文字です。 昔は、厳密な文字コードを当てにするわけでなく、独自の解釈でこの文字を回転させるブラウザが多くありました。 回転させたくないとなると、フォント制作時に、グリフのほうを先に回転させておいて、90度回転が都合2度行われることを期待して、最終的に正立で表示する、という仕組みが取られました。

見た目では同じですが、フォントと、ブラウザの世代が合っていないと、うまくいきません。 フォントだけをバージョンアップすると、また方向が違ってきたりします。 なるべく新しいブラウザと新しいフォントの組み合わせでないと、うまく向きが定まらないという、不整合が起きやすい解決方法というわけです。

もっとややこしい例として、U+3030 Wavy Dashを挙げましょう。

wavy dash

VOはTrです。 横書きでは普通の向きでよいですね。 縦書きでは、上下を向くようにしてほしいです。 UTR50ではTrだから、縦書きグリフがあればそれを使い、なければ横グリフを回転させればよいことになります。 しかし、CSSの仕様に素直に従うと、縦書きグリフがなかったら横向きのまま表示しよう、と書いてあるので、普通は横向きになってしまう。 一応、但し書きとして「回転してもよい」とは書いてあるので、仕様上、絶対に回転しないわけではないですが、一体どちらに従ったらよいのか非常に曖昧に書かれていて、困ったことになっています。

余談

予想ですが、このあたりは、仕様変更が遠からず入りそうな気がしています。 CSSの仕様は、UTR50が確定する前に決められたようだし、UTR50も議論が紛糾してバージョンがいくつかあります。 UTR50は、2014年初頭にはまだドラフトで、6月に正式版になりました。 正式版になってからもバージョンアップはすることがありますが、公開されて効力があります。

縦中横 (text-combine)

みなさん縦中横ってご存知でしょうか。 エジプトに行った方はよくご覧になっていると思いますが、どこにでもあるヒエログリフを例に説明します。

Hieroglyph

ヒエログリフは、縦にも横にも書ける体系です。 この文章は縦に進んでいますね。起点は左端の行です。

Hieroglyph

細かく見ていくと、文字の大きさが区々まちまちであることに気づきます。 縦書きに1文字ずつ進むのではなくて、漢字を組んでいるかのように、字が横にも積み重なっています。 これが「縦中横」です。

続けて、東アジアの現用体系でも見てみましょう。 CSSで扱うのは、どちらかというと現用のほうですね。

heisei

平成27年8月31日。関東では夏休みが終わる日です。 この中の「24」や「31」が、日本語の縦中横です。 縦書きの中に横書きが出る、ということで「縦中横」と呼ばれています。 数字に使う例が多いですが、「?!」などの記号にも使います。 また、リスト項目の(1) (2) (3) (あ) (い) (う)などのマーカーも縦中横に当たります。

特徴

縦中横では、常に文字を正立させるという特徴を持っています。 決してsidewaysになったりしません。

また、縦中横では横書きのグリフが使われます。 なぜかというと、名称の通りに、縦書きの中の「横書き」だからです。

高さは全角1文字分で、漢字とともに積み重ねた場合に等間隔に見えるようになります。 幅も全角1文字分に収めます。

縦中横の中のそれぞれにletter spacingを入れても、仕様上、無視されます。

縦中横の幅

紙の出版物では、同じように全角1文字分のボックスに収めるスタイルが多いようですが、3桁や4桁の場合にはみ出したり、フォントによっては2桁でもはみ出すこがあるようです。 もちろん、はみ出すとしても、左右の行にかからない範囲です。

CSSの仕様では現在のところこうなっています

If the combined text is wider than 1em, the UA must fit the contents within 1em, see below. The resulting composition is treated as a single upright glyph for the purposes of layout and decoration.

(もし組み合わせたテキストが1emの幅より大きくなるときは、UAは下記のように1emの幅に収まるようにしなければならない。 結果、1つの正立した文字のようにレイアウト上は扱われる。)

全角1文字分のボックスに収めることが明示されていて、extentも1em、measureも1emになります。 位置は、縦横の真ん中に置くとなっています。 幅が1emを超える場合、どのように縮めるかは仕様ではあまり明確に決まっておらず、アプリケーション任せになっています。

例えば、数字には半角と全角があります。 HTMLで全角の24に対して縦中横が指定されている場合、全角の文字を2つ並べてしまうと幅が2emになってしまいます。 そこで、仕様上、まずは24を半角にしてから使うこととなります。

また、予め2文字・3文字・4文字の縦中横用に圧縮されたグリフを指定する方法もあります。 これはOpenTypeのフォントの中にある、hwid・twid・qwidのグリフを呼び出す機能があります。 hwidはhalf-width、twidはthird-width、qwidは、quarter-widthの略です。 アプリケーションは縦中横の桁数を見て、フォントにその桁数のためのグリフがあればそれを使い、無ければ独自に圧縮します。 独自の圧縮を行うときは、文字の形を横方向に狭くなるように変形し、1文字分の領域に収めることになっています。

1emの幅から意図的にはみ出てレイアウトしたいときは、縦中横の機能は使えません。 inline-blockで横書きのブロックを作るしかないようです。 しかし、inline-blockは圧縮の指定がないため、文字の幅が広すぎると思っても、任意に圧縮するようなことはできません。 あまり縦中横の代替としては使えないかもしれません。

縦中横の内部

こんな縦中横は嫌だ!という画像を用意してみました。 赤い傍線を引いたものです。

heisei with line

縦中横は2桁の数字の組み合わせですが、組み合わせた結果は1文字として扱ってほしいですよね。 傍線を引いた場合、「2」と「4」の間に傍線が入ってほしくないわけです。 傍線は、組み合わせた結果を1字として扱い、その横に付くのが良いのです。

この挙動をするために、組み合わせた結果の字は、U+FFFC Object Replacement Characterとして扱われます。 text-decorationの傍線などは、このU+FFFCに対して傍線を引く、という処理になります。

U+FFFCは他にも、画像などを文字と一緒に改行処理をするときに、画像を便宜上文字として代替するために使われます。

ちなみに、よく似た文字として、U+FFFDがあります。 これはReplacement Characterといって、文字化けしたものを「?」のような文字で表示するものです。 よく「豆腐」と言われる文字ですね。 言葉が似ているので、間違う人が多いし、アプリケーションの実装でも間違っていることがたまにあります。

折り返し判定のときは、どうでしょう。 「24」という特殊な文字として改行できるか判定するか、または「2」「4」という元の字で解釈して、改行できるか判定するのか。 答えは、個別の字として判定されます。 平成の「成」と「2」の境界、「4」と「年」の境界、で判定が走ります。 折り返し判定の結果を見て、縦中横の字として合成したものが、前の行に付いたり、次の行に送られたりします。

::first-letterは「2」「4」どちらを指すでしょう。 これも仕様で決まっていて、first-letterは「24」を1文字として扱うことになっています。

text-align: justifyを指定したときに、字の間隔が広がるかどうかは、「2」「4」別ではなくて、FFFCとして扱います。

余談

悩ましい「1文字の縦中横」について紹介します。 正立する・横書きグリフが使われる、という特徴から、この表記がよく使われます。

ある文字を正立させたいとき、text-orientation-uprightプロパティで方向指定する方法では、意図通りにならないことがあります。 上で説明した波ダッシュ(〜)やdouble vertical lineの問題のことです。 double vertical lineは、フォントによっては、縦書き時に回転するようにデザインされています。 また、ほかのフォントでは、正立するようにデザインされています。 本当はフォントのほうの問題なのですが、出回っているフォントの縦書きグリフの有無によって、挙動が変わってしまうので、確実性がありません。 これではtext-orientation-uprightプロパティを安心して使えません。

どこかに代替機能がないかということで、1文字の縦中横という形が考案されました。 この表記を使うと、text-orientation-uprightプロパティを使うよりも安全に文字が正立します。 横書きですから、縦書き用のグリフは呼び出されることはなく、横書きの文字だけが呼び出されます。フォントの縦書き対応に影響されることがありません。

これは本来の縦中横の存在異義とは違う、悲しいオーサリング事情と言えます。 電書協ガイドラインで推奨となっていますが、もし仕方なく使う場合、本来求められていた機能ではないことを片隅に置いていただければと思います。

プロパティ

縦中横を指定するCSSプロパティは、よく変わります。

2011年5月31日以前にはtext-combineでした。このプロパティにhorizontalを指定すると、タグで囲われた文字が縦中横となります。

その後、2011年9月1日にtext-combine-horizontalに変わります。

最新の仕様ではtext-combine-uprightに名称が変更されています。 これを次の項で詳しく説明します。

自動縦中横

2015年8月時点の最新はtext-combine-uprightです。 下記のような値を指定できます。

  • none
  • all
  • digits 2

自動縦中横の仕様が増えました。 値にdigits 2のように、文章中で自動的に縦中横にしたい数字の桁数を指定します。 数字2桁を見つけて、縦中横を適用してくれる、という仕様です。 普通にやると、<平成>span<27>/span<のように、文章中のあちこちをspanで囲ってマークアップする必要があって、手間がかかりますが、自動縦中横では文書全体にこのスタイルを適用しておくだけで済みます。 ひとつひとつ箱を用意するのが面倒なので、全体的に自動で適用してしまいたいという要望が出たのでしょう。 自動縦中横には出版社が興味を持っていて、CSSの仕様に入れられたようです。

指定できる桁数は2から4です。 なお、alphabetを自動縦中横する機能はありません。

ここで問題です。 「10,000」のようにコンマの入った表現は、どうなるでしょうか。 digits 2を指定しておくと、コンマのせいで「10」と「000」が分かれてしまい、2桁以下である「10」だけが立ってしまいます。 これは意図しない挙動ですので、spanを明示的に使い、縦中横を使用しないマークアップにしておく必要があります。

ベースライン

長くなりましたが、これで最後の項目です。

下の図は第一回の資料からで、ベースラインについて復習しておきましょう。

baseline

ベースラインより上をアセント、ベースラインより下をディセントと呼びます。

baseline aligned

上のサンプルでは、AppleとOrangeの文字サイズをあえて変えてあります。 文字サイズが変わっていても、ベースラインが揃っているのがわかります。 アルファベットでは、小文字のpやgの下にある足の部分が、ベースラインより下にはみ出るのが自然です。 日本語の文字は、字の下端がベースラインです。 文字が線上に綺麗に揃っているものを見ると、美しい組版という感じがしますね。

縦書きのベースライン

英語を縦(正立)にしたり、日本語を縦にした場合、アセントやディセントは、定義上は無くなります。 「g」の足はディセントと呼んでよいですが、アルファベットが正立の場合、縦に積むのですから、ベースラインに沿うような方向のアセントやディセントではありません。 仮に、ベースラインで揃えてしまうと、下のようにすべての文字が重なってしまいます。

baseline vertical

このため、縦書きで正立するときは、アセントやディセントは定義できません。 かわりにどうするかというと、セントラルベースラインというものがあります。 グリフの中央、つまりemボックスの中央を指す、この用語が使われます。 日本語は、漢字を囲う領域の中央がセントラルベースラインになります。 ちなみに、この用語は横書きでも有効で、漢字の中央を通るラインを指します。

slide

縦書きのときの文字方向がmixedとuprightのときに、セントラルベースラインがデフォルトで選ばれます。 文字方向がsidewaysのときは、alphabetic baselineが選ばれます。

この図で大事なのは、日本語が回転しているところではなくて、AppleやOrangeが揃っている位置が違うところです。 青い線で、英字の通常のベースラインを示しましたが、ここでは揃っていませんね。 セントラルベースラインのほうは、Appleが少し右に寄って、漢字の中央に揃うようになっています。 sidewaysのとき、アルファベティックベースラインを採用したほうは、AppleとOrangeが左のほうで揃っていますね。

余談

middleとセントラルは違います。 第一回のPart2で解説しています。 middleは、「baselineから、小文字のxという文字の高さまでの半分」のことで、フォントにもよりますが、漢字の中央には正確に合いません。

ドミナントベースライン

親と子が、ベースラインをどう扱うのか見てみましょう。 基本的には、親のドミナントベースラインに、子の同じベースラインが揃います。 具体的には、alphabeticとcentralのどちらがドミナントかを示します。 第一回で取り上げた、vertical alignのベースライン指定で、どちらを選ぶか、というのがドミナントベースラインです。

「ドミナントベースライン」とは、「支配的なベースライン」という意味で、ある行において子を支配するベースラインのことです。 親と子が、両方とも同じベースラインに設定されている場合、先程出したsidewaysおよびmixedの例のように、親も子も同じベースラインで揃えられます。

さて、ここで、次のようなHTMLを想定してみます。 最初のspanで、AppleとOrangeを括っています。

1
2
3
4
5
6
7
8
9
<p style="text-orientation: mixed">
    <span style="text-orientation:sideways">
        Apple
        <span style="font-size:150%">
            Orange
        </span>
    </span>
    こんにちは
</p>

このような場合、まずspanの中のベースラインでAppleとOrangeが揃えられ、それを囲うボックスが日本語のセントラルと揃います。 図を使って解説しましょう。 青い線がセントラルベースライン、赤い線がアルファベティックベースラインです。

slide

AppleとOrangeを囲うspanには、sidewaysが指定されています。 sidewaysということは、alphabeticがここではドミナントベースラインになります。 つまり、青い線でAppleとOrangeが揃います。

次に、日本語を含んでいる親のベースラインに揃えます。 親はpで、pにはmixedが指定されています。 mixedということは、セントラルベースラインですね。 AppleとOrangeの組み合せでできたボックスは、その中央がセントラルベースラインです。 日本語は、漢字の中央がセントラルです。 全体としては、図の赤い線で揃います。

Appleには赤い線が2つ見えますが、左のほうの線は、本来あるセントラルベースラインです。 右のほうにある線が、AppleとOrangeを含んだボックスのセントラルベースラインで、全体はこれで揃えています。

ベースラインを指定して揃えるということは、アプリケーションによっては10年以上前から当たり前のように実装されている、新しくない概念です。 Microsoft Wordなどは当たり前のように実装していますが、Webではまだ難しいです。 デザイナが他のアプリケーションで作ったものが、HTMLで再現しにくいのがよくわかります。 Webのほうが遅れていることがわかり、ちょっと悲しくなります。

余談

最後の余談として、atomic inlineを説明します。

slide

食べるラー油の絵は、by坂原さん2014©です。 タコではなくてラー油です。

タコではなくてラー油です。

正立の英字にはアセントやディセントがないことがわかりましたが、画像はどうでしょう。 画像のような、インラインブロックにも、アセントやディセントはありません。 アルファベティックベースラインはどうやって決めるのでしょうか。

答えを言うと、画像は、一番下をアルファベティックベースラインに、中央をセントラルベースラインにします。 これは単なる決まりですので、なぜこのようになっているのか考察は入れず、丸暗記でよいかと思います。

おわりに

長く続いた第二回の書き起しは、以上となります。 9月に勉強会の予定があります。 詳細については、最近設置いたしましたCSS研究部のWikiをご覧ください。