anti scroll

ブラウザと小説の新しい関係を模索する

CSSとDOMの境界、あるいはリスト組版がテーブル組版の親戚である件について

http://tb.antiscroll.com/static/nehan-demo#list

このデモですけど、ブラウザの大きさを変えると、リフローすることに気付いた人はいるでしょうか。

こういうデモで、テーブル組版や回り込み処理を見せると「おお」となる人が多いんですけど、リスト組版を見せても「で?」という人が多いと思います。

しかし、一見すると単純に見えるリスト組版ですが、実はテーブルの組版とよく似た複雑な組版なのです。

並列組版

nehan.jsでは、list-style-position:outsideかつdisplay:list-itemな要素と、display:table-rowな要素は、どちらもParallelGenerator(並列組版)のサブクラスで実装されています。

並列組版とは、複数の組版要素を同時並行的に行う組版です。

特徴としては、複数の子要素が矛盾なく表示されるための「前計算」を必要とするケースが多い、というのがあります。

例えばテーブルなら、各セルのサイズをどう割り当てるのか、事前に何らかの計算が必要なのは、なんとなく想像がつくと思います。

でもリストはどうでしょうか?

「リストなんて、単にテキストの先頭にリストマークの添字を足すだけじゃないの?」と思う人もいるかもしれません。

この指摘は、list-style-position:insideなら、まあそのとおりなのです。

しかしlist-style-position:outsideのときは、様相が異なります。

まずはUL>LIが書かれたHTMLを、適当なブラウザで表示させみてください。

<ul style="list-style-position:outside">
  <li>日本国民は、正当に選挙された(以下略)</li>
</ul>

CSSとDOMの境界

さて、表示されたリストですが、各リスト・アイテムの「リストマーク」は、マウス等ではテキスト選択できません。

f:id:convertical:20151203101342p:plain

つまり、このリストマークは、ユーザーがDOM操作では触れない組版要素になっています。

これが「CSSとDOMの境界」です。

これだけじゃありません。

list-style-positon:outsideのときは、リストの要素が一行を溢れても、リストマークの横幅だけ常に内容がインデントされています。

f:id:convertical:20151203101357p:plain

つまり空白の一列が割り込んでいるわけです。

この空白も、liマークアップに対するmarginpaddingで実現されているわけではないので、CSSとDOMの境界と言えます。

正確にリストを組版するためには、これらの境界要素に関するサイズ配分を事前に計算する必要があるわけです。

で、こういう性質を知っていると、例えばブラウザにとってどんなリストが意地悪なのかが、なんとなく予想できます。

意地悪な組版

例えばOL>LI*1000マークアップで、それぞれのリストを1em, 2em, 3emの文字サイズで順に表示させてみましょう。

<style type="text/css">
ol{ list-style-position:outside; }
.hoge{ font-size:1em }
.hige{ font-size:2em }
.hage{ font-size:3em }
</style>

<ol>
  <li class="hoge">hoge</li>
  <li class="hige">hige</li>
  <li class="hage">hage</li>
  <!-- 以下1000行まで続く -->
</ol>

どうしてこれが意地悪なのかというと、このリストを正しく表示するためには、1000行の添字が使うであろう数字文字列の最大幅を事前に計算する必要があるからです。

じゃないと、適切なインデントを実現できませんよね。

しかしchrome/firefox/safariにこれを表示させると、いずれも桁数が大きくなったところで、以下のようにリストの添字部分が「画面の左側」に見切れてしまいます。

f:id:convertical:20151203101412p:plain

body{margin-left:3em}みたいな設定をしていたってダメです。左の限界を突破して表示が切れます。

もちろん普通に考えると、li要素にそれぞれ違う文字サイズを付与することなんて考えにくいことなので、実用上は問題ないのです。

ただ正確に扱おうとするなら、リスト要素もテーブル組版と同じく、先に必要領域を計算する必要のある重い組版に該当するわけです。

この1000行のリストが、現状のブラウザで瞬時に表示されるのは、単に各ブラウザが厳密な計算をサボっているだけで、組版処理そのものが単純だからではありません。

というわけで、リストの組版も(テーブル組版ほどではないですが)、なかなかに複雑な処理なのです、というお話しでした。