擬似要素と数値文字参照を使ってキリル文字のアクセント記号を表示する

ロシア語の勉強を始めたので、キリル文字のアクセント記号を表示できないかな?と考えてみました。現時点での最適解と思われるものを見つけたのでシェアします。

インターネットエクスプローラ?なにそれ?

アクセント記号を重ねて表示するのだ!

ロシア語のアクセントであるударениеはひとつの単語中に一箇所存在します。そして必ず母音に表示される。ёみたいにウムラウトっぽい記号のある母音は必ずアクセントがあるので、こういうのはアクセント記号を表示しなくていい。

というわけでロシア語に関して言えば該当する文字にアクセント記号「´」を重ねるだけでいいのだ。大文字はともかく、小文字なら干渉することはない。

.acc::after {
  content:"\00b4";
  margin-left:-0.5em;
  margin-right:0.15em;
}
.nobr {
  white-space:nowrap;
}

このようにふたつクラスを用意して、単語そのものはnobrクラスで、アクセント記号を置く文字はaccクラスで括ってやれば良い。

<span class="nobr">удар<span class="acc">е</span>ние</span>

以下御託。

アクセント記号付きの文字コードとアクセント記号の文字コード

ラテン文字についてはラテン特殊文字|図書館員のコンピュータ基礎講座にあるように、アクセント記号付きの文字があるのでこれを使えば良いのです。

発音記号|KumaRocketによると合字用のアクセント記号文字参照コードというのがあって、アクセント記号の文字コードはふたつ。例えば「´」であれば&#180;(&#xb4;)はアクセント文字単体で、&#769;(&#x301;)は直前の文字と合成される文字になります。

じゃあこれを使えばいいかと思っていたんですが、どうも様子がおかしい。Google Fontsのキリル文字フォントMerriweatherが綺麗なのでWebフォント指定しているんですが、合字するとデフォルトのフォントに戻ってるっぽい。

各フルブラウザでの確認結果を以下に示します。OSはmacOS High Sierra 10.13.4で、Windowsの方はParallels仮想環境下でのWindows 10 Home 17133.1です。

  • Safari 11.1(Mac)
    Mac版Safari
  • Chrome 65.0.3325.181(Mac)
    Mac版Chrome
  • Firefox 59.0.2(Mac)
    Mac版Firefox
  • Opera 52.0.2871.64(Mac)
    Mac版Opera
  • Edge 42.17133.1.0(Windows)
    Windows版Edge
  • Chrome 65.0.3325.181(Windows)
    Windows版Chrome
  • Firefox 59.0.2(Windows)
    Windows版Firefox
  • Opera 52.0.2871.30(Windows)
    Windows版Opera
  • Internet Explorer 11.1.17133.0(Windows)
    Windows版Internet Explorer

文字参照の合字フォント付加に関して言えば、皮肉なことにWebフォントが適用されていないieの合字が一番まともな結果に終わっています。

とは言えもはや21世紀だ。デロリアンは時空を超えてやってきたし、HAL9000はモノリスに取り込まれてしまったのだ。今更手間暇かけてie対応をすることもない。アクセント記号が表示されないだけのこと。

擬似要素と文字サイズと改行に関する注意

ということで冒頭に戻って、cssでアクセント記号をアクセント対象文字に重ね合わせることにしました。

::after擬似要素で文字参照を表示する

::after擬似要素を使って文字参照コードを表示する場合、htmlで指定するフォーマットではうまく行きません。擬似要素[::before]や[::after]にて特殊文字・機種依存文字を表示する方法|bitstar スタッフブログにある通り、16進数表示の数値文字参照の「&#x」を「\00」に置き換えて末尾の「;」を削除する必要があります。

擬似要素を使わずに直接文字参照を埋め込んでも結果は同じになるんですが、html文書はタグを外した際にプレーンテキストになるのが基本。直接埋め込んだ文字参照をcssで移動させるのでは単語が分断されて意味が通じなくなってしまいます。

なのでもはや21世紀ですしcss3使っちゃえばいいよねということでieを切り捨てました。

1emの文字幅

冒頭のコードを見てもらえばわかるように、左マージンをコントロールしてアクセント記号を左(前の文字側)に0.5em移動することでフォントの重ね合わせをしています。

0.5em?1文字じゃないの?1emの・・・幅?|Lv1プログラマの誰得メモによるとemって文字幅じゃなくて文字高さなんだそうで。。。

だから半角文字(といっても今時プロポーショナルフォントだけど)の場合、1emは2文字分の文字幅になっちゃう。-1em指定したら変なところにアクセントがついてびっくりしたよ!

改行位置のコントロール

さて、前項では主だったフルブラウザでの見ばえしか載せていませんが、モバイルブラウザでも確認しています。

iOS 11.3のSafari(iPhone SEとiPad mini2)、Android 7.0の標準ブラウザ(Jelly Pro)でちゃんと表示されますが、nobrクラスで括ってやる前はアクセント記号の直前で改行が入ることがありました。

ブラウザとしては文字列の意味までは理解しませんから、htmlタグの挿入位置は何らかの区切りであると解釈してしまうんでしょうね。spanタグで括られたアクセント対象文字まで表示したら、画面幅が足りなくなったのでそこで改行を挿入し、accクラスの::after擬似要素としてはそのまま行頭にアクセント記号を表示してしまうと。

仕方がないので冗長ですが、nobrクラスで単語単位で括ってwhite-space:nowrap;を適用しました。

結構手間を掛けて見ばえを整えているのだよ。