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の境界
さて、表示されたリストですが、各リスト・アイテムの「リストマーク」は、マウス等ではテキスト選択できません。
つまり、このリストマークは、ユーザーがDOM操作では触れない組版要素になっています。
これが「CSSとDOMの境界」です。
これだけじゃありません。
list-style-positon:outside
のときは、リストの要素が一行を溢れても、リストマークの横幅だけ常に内容がインデントされています。
つまり空白の一列が割り込んでいるわけです。
この空白も、li
マークアップに対するmargin
やpadding
で実現されているわけではないので、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>
</ol>
どうしてこれが意地悪なのかというと、このリストを正しく表示するためには、1000行の添字が使うであろう数字文字列の最大幅を事前に計算する必要があるからです。
じゃないと、適切なインデントを実現できませんよね。
しかしchrome/firefox/safariにこれを表示させると、いずれも桁数が大きくなったところで、以下のようにリストの添字部分が「画面の左側」に見切れてしまいます。
body{margin-left:3em}
みたいな設定をしていたってダメです。左の限界を突破して表示が切れます。
もちろん普通に考えると、li要素にそれぞれ違う文字サイズを付与することなんて考えにくいことなので、実用上は問題ないのです。
ただ正確に扱おうとするなら、リスト要素もテーブル組版と同じく、先に必要領域を計算する必要のある重い組版に該当するわけです。
この1000行のリストが、現状のブラウザで瞬時に表示されるのは、単に各ブラウザが厳密な計算をサボっているだけで、組版処理そのものが単純だからではありません。
というわけで、リストの組版も(テーブル組版ほどではないですが)、なかなかに複雑な処理なのです、というお話しでした。