displayについて本気出してW3Cの仕様書読んでみた

こんばんは。
CSS Property Advent Calendar 2013 8日目のエントリーです。

非常に地味な display のお話です。
なお、flexboxの話をし出すと、それだけで1エントリーくらいの分量になってしまうので、css2.1までの話をします。
flexbox関係は昨日担当の富田さんがまとめてくれてるので、そちらを参考にしましょう。
flexboxの旧仕様、改定仕様、現行仕様の一覧 « LINE Engineers’ Blog

では、まずブロックとインラインを理解するためにボックスモデルから復習していきます。

ボックスの種類

w3cの仕様書では先に「ブロックレベル要素とブロックボックス」次に「インラインレベル要素とインラインボックス」といった感じで説明されていますが、ちょっと趣向を変えて、ブロックとインラインを対比しながら見てみます。

ブロックレベル要素とインラインレベル要素

ボックスのレベルの話。

ブロックレベル要素

ブロックレベル要素は、ソース文書でブロック(段落など)として視覚的にフォーマットされた要素のことです。
‘display’プロパティの’block’、’list-item’、’table’値は、要素をブロックレベルにします。
御存知の通り、ブロックレベル要素は縦方向にスタックされていきます。

インラインレベル要素

インラインレベル要素はソース文書のうち新しい内容ブロック整形しない要素であり、内容は複数行にまたがります。(たとえば、段落内の文字強調や、インライン画像など)。
‘display’プロパティの’inline’、 ‘inline-table’、’inline-block’値は、要素をインラインレベルにします。

ブロックボックスとインラインボックス

実際に生成されるブロック整形コンテキストに関わるボックスの話。

ブロック

ブロックレベルボックス

ブロックレベルボックスは、ブロックレベル要素によって生成されたボックスです。
各ブロックレベル要素は、子孫ボックスや生成されたコンテンツが含まれており、また、任意の位置決め方式に関与するボックスである主ブロックレベルボックスを生成します。

一部のブロックレベル要素(’list-item’要素)は、主ブロックレベルボックスに加えて追加のボックス(マーカーボックス。簡単に言うと’list-style-type’とか’list-style-image’で決めるもの)を生成することがあります。この追加ボックスは主ボックスを基準にして配置されます。

ブロックコンテナボックス

置換要素とテーブルボックスを除くブロックレベルボックスは、ブロックコンテナボックスでもあります。
ブロックコンテナボックスはブロックレベルボックスのみを含むか、**インラインレベルボックスのみを含みます(匿名ブロックボックスと匿名インラインボックスの話)。
ブロックレベルボックスとブロックコンテナボックスは別で、すべてのブロックコンテナボックスがブロックレベルボックスとは限りません。
非置換テーブルセルや非置換インラインブロックは、ブロックレベルボックスではありませんが、ブロックコンテナでです。

ブロックコンテナでもあるブロックレベルボックスをブロックボックスと呼びます。

非常に雑な言い方をすれば、ブロックレベルボックスがボックスの外側の話でブロックコンテナボックスがボックスの内側の話と言う感じでしょうか。

(置換要素:img, button, input, object等、当該要素の属性に入力される値などによって内容が置き換えられ、その寸法で認識される要素)

インライン

インラインレベルボックス

インラインレベルボックスはインラインレベル要素によって生成されるボックスです。 これは、インライン整形コンテキストに加わるために、ボックスとして定義されたものです。

インラインボックス

インラインボックスは、インラインレベルボックスであり、それらのコンテナのインライン整形コンテキストに加わるボックスでもあります。 ‘inline’の’display’値を伴なう非置換要素は、インラインボックスを生成します。

atomic インラインレベルボックス

インラインレベルボックスであるが、インラインボックスでないもの(置換要素、インラインブロック要素、インラインテーブル要素等。幅・高さの指定できるインラインレベルボックス)は、単一の不透明なボックスとしてインライン整形コンテキストに関与するため、atomic(分割不能・不可分な)インラインレベルボックスと呼ばれます。
atomicインラインボックスは、インライン整形文脈内で複数の行にわけることが出来ません。

匿名ブロックボックスと匿名インラインボックス。

匿名ブロックボックス

次のようなHTMLマークアップされた文書で:

<div>Some text<p>More text</p></div>

<div>はインラインコンテンツとブロックコンテンツの両方を持つように見えます。しかし、整形の定義のわかりやすさのために、”Some text”の周囲に匿名ブロックボックスがあるとみなします。

言い換えれば、ブロックコンテナボックス(上記の例では<div>に対して生成される)が、内部にブロックレベルボックス(上記の例で P)を持つ場合、ブロックボックスの内部はブロックレベルボックスのみになるよう強制することになります。

block

匿名インラインボックス

次のようなHTMLマークアップされた文書で:

<p>Some <em>emphasized</em> text</p>

<p>は内部にインラインボックスを持つブロックボックスを生成します。”emphasized”のボックスは、インライン要素(<em>)によって生成されたインラインボックスですが、他のボックス(”Some”と”text”)はブロックレベル要素(<p>)によって生成されたインラインボックスです。後者は、関連するインラインレベル要素を持たないため匿名インラインボックスと呼ばれます。

inline

display

ここから、cssプロパティのはなしです。

displayは要素に使用されるレンダリングボックスの種類を指定します。 HTMLでは、デフォルトの表示プロパティの値は、HTMLの仕様か、ブラウザ/ユーザのデフォルトのスタイルシートに記述から取られています。

初期値:上記の通り
適用対象:全要素
継承:しない
アニメーション:不可

: none

要素を整形構造に出現させません。すなわち、視覚メディアにおいて要素はボックスを生成せず、レイアウトに影響しなくなります。
不可視のボックスを作成するわけではなく、ボックスを作成しないのです。
子孫要素もいかなるボックスも生成しません。要素とその内容は整形構造から完全に削除されます。この動作は、子孫での’display’プロパティの設定によって上書きされません。
なお、当然ですがDOM上は存在します。

: inline

1つ以上のインラインボックス要素を生成します。

: block

ブロックボックス要素を生成します。

: list-item

コンテンツのための主ブロックレベルボックスに加えて追加のマーカーボックスを生成します。

: inline-block

インラインレベルボックスコンテナを生成します。 先で説明したatomicインラインレベルボックスです。
MDNに「単一のインラインボックスであるかのように周囲のコンテンツの流し込みが行われる、ブロックボックス要素を生成」と解説されていましたが、inline-blockはブロックコンテナではありますがブロックレベルボックスではなくインラインレベルボックスなのでブロックボックス要素とは呼べず、誤りです。。

: table

<table> 要素と同じように動作、つまりブロックレベルのテーブルを生成します。

: inline-table

インラインレベルのテーブルを生成します。
またMDNに「インラインボックスとしてではなく、ブロックレベルボックスとして動作します。」とありますが、ブロックコンテナのインラインレベルボックスです。

: table-row

<tr>要素と同じように動作します。
指定要素はセルの行となります。

: table-row-group

<tbody>要素と同じように動作します。 指定要素グループが1つ以上の行となります。

: table-header-group

<thead>要素と同じように動作します。 行グループは、常にすべての行と行のグループの前に、かつ任意の上部のキャプションの後に表示されます。 テーブルが ‘display: table-header-group’ をもつ複数の要素を含む場合は、1行目のみヘッダとして描画され、他の行はあたかも ‘display: table-row-group’ を持つかのように扱われます。

: table-footer-group

<tfoot>要素と同じように動作します。 行グループは、常にすべての行と行のグループの後に、かつ任意の下部のキャプションの前に表示されます。
テーブルが ‘display: table-footer-group’ をもつ複数の要素を含む場合、1行目のみフッタとして描画され、他の行はあたかも ‘display: table-row-group’ を持つかのように扱われます。

: table-column

<col>要素と同じように動作します。
指定要素は、セルの列を記述します。

: table-column-group

<colgroup>要素と同じように動作します。
要素グループは、1つまたは複数の列があることを指定します。

: table-cell

<td>要素と同じように動作します。
要素がテーブルのセルを表すことを指定します。

: table-caption

<caption>要素と同じように動作します。
テーブルの説明文を指定します。’display: table-caption’をもつすべての要素はテーブルにおけるcaptionのように描画されなければならなりません。

display: table、inline-table、table-xxxについて

これらの’display’値をもつ置換要素は、レイアウト中にその指定されたdisplay型として扱われます。
たとえば、’display: table-cell’に設定される画像は使用可能なセル空間を埋め、その寸法は通常のセルと同様に、テーブルのサイズアルゴリズムに貢献するかもしれません。

‘table-column’または’table-column-group’に設定される’display’をもつ要素は、レンダリングされません(’display: none’をもつ場合とまったく同じ)が、それらが表す特定の列のスタイルを風洞する属性を持つかもしれないので、有用らしいです。

なお、最近ではいつまでも地雷臭が抜けないflexboxの代わりに、レスポンシブなサイトを作る際に順番を入れ替えたりするのにも使われたりもしているようです。
初日げこたんの2位参照:僕の好きなCSSのプロパティ2013 – < /gecko >

: run-in

・run-inボックスにブロックボックスを含むなら,run-inボックスはブロックボックスを生成します。
・run-inボックスの後に,フロート配置でも絶対位置決めでもない弟ブロックボックスがつづく場合,run-inボックスはそのブロック内の最初のインラインボックスになります。ただし弟のブロックがすでにrun-inボックスで始っているか,run-in自身なら例外です。
・それ以外では、run-inボックスはブロックボックスになります。

run-in要素は視覚的に後続ブロックボックスの一部のように見えるにも拘らず,それでもDOMツリー上にある親からプロパティの値を継承します。 すなわち,一見して親であるかのように見えるブロック要素から値を継承される訣ではない,という事です。

: compact

面白いんですが、Operaがレンダリングエンジンをprestoからwebkitに変えたことで、対応ブラウザがなくなったので割愛します。

以上、W3Cの仕様書を日本語訳しただけのようなエントリーでした。

明日、8日目はくぼしょーさんです。
お楽しみに!