pixiv insideは移転しました! ≫ https://inside.pixiv.blog/

HTMLで日本語を書きたいプログラマーの永遠の悩みを解決するCSS3のSegment Break Transformation Rules

この記事はピクシブ株式会社 Advent Calendar 2015 の9日目の記事です。

qiita.com

こんにちは。アルバイトのhakatashiです。以前の小説縦書き機能についてのpostではたくさんの拡散を頂きありがとうございました。おかげで褒賞のAmazonギフト券3000円を入手できました。ウハウハ。そして拡散に協力してくれた後輩へのおごり代に消えました。どうやら世の中は上手くできているようです。

今回は、pixivにはあまり関係ないですが、普段携わっている小説関係の業務にかこつけて、CSS3のあまり知られていない新機能、Segment Break Transformation Rules と、それを今すぐ使うための自作ライブラリを紹介します。前回と違ってがっつりエンジニア向けの内容となっているので、まったりと書いていきます。

HTMLで日本語を書きたい人間の一般的ストーリー

突然ですが、みなさんはパソコンで日本語を書きますか? APIドキュメントでも小説でも、明日締切のレポートでも始末書でもなんでも構いません。書きますね? 書くはずです。

日本語の文書を書くなら、優れたセマンティクスとレンダリングエンジンをそなえたHTMLで書きたいと思うはずです。そうですね? Wordとか使いませんね? いえ、MarkdownでもJadeでも、いずれHTMLになるフォーマットなら何でも構いません。HTMLで書きますね? 書くはずです。

そしてHTMLで日本語を書くなら、たとえ小説であろうとGitでバージョン管理をしたいと思うはずです。プログラマーの皆さんはバージョン管理の重要性を知っています。宮沢賢治がGitを使っていれば『銀河鉄道の夜』の初稿も散逸しなかったでしょう。Gitでバージョン管理しますね? するはずです。

そこで、あなたはかつてLaTeXでそうしたように、あるいは英語圏の人間がHTMLでそうしているように、段落の好きな場所に改行を入れてHTMLを書くはずです。例えば、次のように。

<p>
    CSS3 の登場によって、これまでほとんど顧みられてこなかった
    アジア圏の組版処理が大きく改善される結果となった。しかし
    <strong>ブラウザのサポートはまだ十分とは言えない</strong>
    だろう。近年はこれをポストプロセッサーによって改善するために
    cssnext などの処理機構がひろく用いられている。
</p>

そしてあなたは記述した内容に満足し、プログラマーのしまむらと呼ばれる[要出典]Bootstrapを身につけ、ブラウザで表示を確認するでしょう。

するとこうなります。

f:id:hakatashi:20151209164950p:plain

なにやらいらない子が混じっています。

これは受け取れません。日本語にうるさいあなたは奇声を上げて部屋中を駆けまわることでしょう。CSSをどう調整してもこの空白を消すことはできないので*1、これを解決するためにはソースコードから改行を取り除くしかありません。

<p>
    CSS3 の登場によって、これまでほとんど顧みられてこなかったアジア圏の組版処理が大きく改善される結果となった。しかし<strong>ブラウザのサポートはまだ十分とは言えない</strong>だろう。近年はこれをポストプロセッサーによって改善するために cssnext などの処理機構がひろく用いられている。
</p>

見ての通り、非常に長い行になります。日本語でHTMLを書こうとするとこのような長い行が大量に出現します。

長行との戦い

Markdownなどでも同じ問題が発生します。現にいま書いているこの原稿でも 段落途中に 改行を入れると こういった 余分な空白が 挿入されてしまいます。Wiki記法でも同じ問題があるため、日本語版Wikipediaでは段落に改行を含めないようガイドラインが定められています

このような長い行は多くの問題を引き起こします。例えば、Vimは非常に長い行を含むHTMLを読み込むと重くなりますAtomは長い行を含むファイルを適切にハイライトすることができません。そして、文章の一部を編集してgit diffを実行すると、次のようなdiffが表示されます。

diff --git a/wtf-is-this-space.html b/wtf-is-this-space.html
index 9a65c52..5201e0c 100644
--- a/wtf-is-this-space.html
+++ b/wtf-is-this-space.html
@@ -4,6 +4,6 @@
 <title>title</title>
 <body class="container">
     <p>
-        CSS3 の登場によって、これまでほとんど顧みられてこなかったアジア圏の組版処理が大きく改善される結果となった。しかし<strong>ブラウザのサポートはまだ十分とは言えない</strong>だろう。近年はこれをポストプロセッサーによって改善するためにcssnext などの処理機構がひろく用いられている。
+        CSS3 の登場によって、これまでほとんど顧みられてこなかったアジア圏の組版処理が大きく改善される結果となった。しかし<strong>ブラウザのサポートはまだ十分とは言えない</strong>だろう。近年はこれをポストプロセッサーによって解決するためにcssnext などの処理機構がひろく用いられている。
     </p>
 </body>

間違い探しの特訓にはもってこいです。

全ての元凶、white-space

このような表示結果になる理由はCSS2.1のwhite-spaceプロパティの定義にあります。

'white-space'が'normal'または'nowrap'に設定される場合、改行文字は、コンテンツのスクリプトに基づいたユーザーエージェント特有のアルゴリズムに従って、空白文字、ゼロ幅スペース文字(U+200B)、または文字なし(すなわち、レンダリングされない)の1つにレンダリングする目的のために変換される。 http://momdo.s35.xrea.com/web-html-test/spec/CSS21/text.html#white-space-model

要するに改行がどのように表示されるか厳密に定義されていません。日本語の文脈においてはLaTeXのように改行を完全に取り除くべきですが、現状それを実装したブラウザはありませんし、そもそも「日本語の文脈」というのが曖昧です。やはり英語で書くことを前提とした実装がほとんどのようです。

CSS3で登場? Segment Break Transformation Rules

white-spaceの定義が含まれるCSS3のTextモジュールは、まだ勧告に至っていないものの、Technical Report版Editor's Draft版ではCSS2.1よりも遥かに複雑なアルゴリズムを定義しています。その中でも特に注目したいのは、厳密に定義されたSegment Break Transformation Rulesです。

Segment Breakとは、要するに要素内における改行のこと。この変換アルゴリズムとして、文字における「全角」「半角」などのプロパティを定義したUnicodeのUAX11を引用して次のような処理を含めています。

Otherwise, if the East Asian Width property [UAX11] of both the character before and after the line feed is F, W, or H (not A), and neither side is Hangul, then the segment break is removed.

ここで挙げられている F, W, H は、日本語ではいわゆる「全角文字」や「半角カタカナ」が該当し、要は日本語文脈では正しく改行を取り除くよう厳密な定義が与えられたことになります。まだCSS3で勧告されることが確定したわけではありませんが*2、将来的にこれが利用できる可能性は極めて高いといえるでしょう。

だが、実装されない仕様に意味は無い

日本語でHTMLを書きたいプログラマーにとっては大ニュースです。しかし、ブラウザの実装が追いついていないため、まだネイティブでは使えません。

これを解決するため、この Segment Break Transformation Rules の仕様を忠実に再現するJavaScriptモジュールを作成しました。名付けてAsianBreakです。

READMEを読んでいただけると分かるかと思いますが、要はこのモジュールに先ほどののHTMLを食わせると、以下のようなものが吐き出されます。

<p>
    CSS3 の登場によって、これまでほとんど顧みられてこなかったアジア圏の組版処理が大きく改善される結果となった。しかし<strong>ブラウザのサポートはまだ十分とは言えない</strong>だろう。近年はこれをポストプロセッサーによって改善するために
    cssnext などの処理機構がひろく用いられている。
</p>

英単語の手前の改行は空白で問題ないので、そこを除いて(必要最低限の)余分な改行とインデントが取り除かれます。これをレンダリングすると、

f:id:hakatashi:20151209184413p:plain

もう余分な空白とはおさらばできます。あなたもAsianBreakをビルドプロセスに組み込んで書き物ライフをエンジョイしましょう!!!*3

まとめ

  • HTMLで日本語は書きづらい
  • CSS3で改善される予定
  • それが待てないなら俺のモジュールを使え

最後は個人的な自作モジュールの宣伝になってしまいましたが、ピクシブ株式会社ではこんなニッチな(だけど重要な)Web技術の話題でテンションが上がるプログラマーを募集しています。一緒に次世代のWebを作りましょう。アルバイトもあるよ

recruit.pixiv.net

*1:word-spacingにマイナスの値を指定するのはフォントに依存しているので環境によって正しく動きませんし、英単語の間の空白も潰れてしまいます。

*2:特にTextモジュールはLevel4がすでに着手済みなので、そちらに見送られる可能性はあります。

*3:そのうちMarkdown用のポストプロセッサーやGulpやGrunt用のプラグインも作成する予定です。