CSSにはtext-emphasis
というプロパティが存在し、これにより圏点/傍点/脇点をテキストに描画できるようになっています。
- CSS Text Decoration Module Level 3 #3. Emphasis Marks
- CSS Text Decoration Module Level 3 日本語訳 #3. 圏点
- text-emphasis (CSS3 Text decoration);圏点のスタイル - CSS3ウェブブラウザ実装メモ - 血統の森 web実験小屋
このプロパティはほとんどのWebブラウザで対応しておらず、WebKit系のブラウザとFirefox Nightlyでしか利用できません。
そこで、このCSSプロパティのPolyfillを作ってみようと考えています。
原理としては、圏点を付ける文字をspan
要素で囲み、その上にCSSで点を描画させるというというもので、点の描画については、既に有効なスタイルを作成してあります。
次の段階として、文字列をspan
要素で囲むスクリプトを作ろうとしたところ、質問のタイトルにある問題にぶつかり先へ進めなくなっています。
text-emphasis
プロパティは、一部の種類の文字に点を描画しないようなのです。
この点を描画しない文字については、仕様書に記載があります:
CSS Text Decoration Module Level 3 #3. Emphasis Marks
The marks are drawn once for each character. However, emphasis marks are not drawn for characters that are:
- Word separators or that belong to the Unicode separator classes (Z*). (But note that emphasis marks are drawn for a space that combines separators with any combining characters.)
- Characters belonging to the Unicode classes for control codes and unassigned characters (Cc, Cf, Cn).
日本語訳を参考にすると、概ね以下のように書かれているのだと推測できます:
(圏点の)マークは、各文字毎に1つづつ描画されます。しかしながら、圏点はこれらの文字には描画されません:
- 単語区切りまたはUnicodeクラスのセパレータ(Z*)に該当する文字。(ただし圏点は、任意の合成文字を兼ね備えるスペースに対して描画される事に注意してください。)
- Unicodeクラスの制御コードと未割り当て文字(Cc, Cf, Cn)に該当する文字。
ここで問題が生じます。
まず、圏点が描画される「文字」が、Unicodeの「データ上での1文字」ではなく「Unicode 拡張書記素クラスタ」を示しているという点です。
Unicode 拡張書記素クラスタが「文字」となっているために、文字列(1字以上の文字データの並び)が1文字と解釈されうるということになります。
しかし、仕様で定義されている「描画されない文字」は「データ上での1文字」となっており、ある文字列(Unicode 拡張書記素クラスタでは「文字」となっている文字列)が「描画されない文字」に該当するのか単純に比較できなくなります。
具体的な例示を出します。
まず、Unicodeのデータで<U+304B U+3099>というデータがあったとします。文字列データとして見た場合、これは'U+304B'(平仮名の'か
')と'U+3099'(合成用濁点)という文字が順に並んだ「2文字の文字列」です。
しかし、実際に描画された場合、この文字は'が
'という、見たまんまの「1文字」になります。これは、後ろの'U+3099'が「結合文字」と呼ばれる特殊な文字で、前方の「基底文字」と一つになることで異なる字形を提供するための、いわば制御コードのようなものだからです。
参考:
そして、Unicode 拡張書記素クラスタでは、この<U+304B U+3099>という「2文字の文字列」が「文字」と解釈されます。当然、圏点も「か」と「濁点」ではなく「が」に1つだけ付けられなければなりません。
'U+304B'と'U+3099'であれば、どちらも「点を描画しない文字」では無いため、何の問題もありません。しかし、これが<U+3000 U+3099>の場合は事情が異なります。
'U+3000'は、日本語の文章でもよく利用される「全角スペース」です。そしてこれに濁点が付くことで、' ゙
'という「1文字」になります。
そして、'U+3000'はUnicodeクラスのセパレータ(Zs)に属する文字です。つまり、'U+3000'は「点を描画しない文字」に該当する文字に当たります。
一方、'U+3099'はUnicodeクラスのマーク(Mn)に属する文字なので、「点を描画しない文字」に該当しません。
このような場合、圏点は描画されるのでしょうか。
<U+3000 U+3099>は、仕様書にある「任意の合成文字を兼ね備えるスペース」に該当します。このため、圏点は描画されるようにも思われます。
しかし、Google Chrome 48.0.2564.116 mで-webkit-text-emphasis
プロパティを使用しテストしたところ、<U+3000 U+3099>に圏点は描画されませんでした。
html
1<p><em class="emphasis_marks">テスト</em> 2<p><em class="emphasis_marks"> ゙</em>
css
1.emphasis_marks { 2 font-style: normal; 3 -webkit-text-emphasis: dot filled; 4 text-emphasis: dot filled; 5}
この他にも、Unicode 拡張書記素クラスタの正規表現パターンを作成することで構造を理解し、このような「任意の合成文字を兼ね備えるスペース」の組み合わせを試してみましたが、<U+3000 U+3099>には圏点が描画されないのに<U+3000 U+FF9E>には描画されたりと、まるで法則性が無いように見えます。
ChromiumやWebKitのソースコードを読めば何か分かるかもしれませんが、私はCやC++が読めませんし、そもそもソースコードのどの箇所が特定のCSSプロパティを処理しているのかや、Unicode文字列がどう処理されているのかさえ把握できないでしょう。
長々と書きましたが、ようやくここで質問になります。
text-emphasis
プロパティが圏点を描画しない文字列(Unicode 拡張書記素クラスタ)の種類は何でしょうか?
もし可能であれば、Webブラウザのレンダリングエンジンの具体的な処理などの情報があると助かります。
あなたの回答
tips
プレビュー