CSS における display, position, float プロパティの相互関係

趣旨

要素を描画する位置や大きさに関係する重要な 3 つのプロパティがある。display, position, float である。この3者は複雑に絡みあっていて、いつも頭が爆発しそうになる。今日は、これを整理することから始めたい。

注意事項

まず注意。
私は W3C CSS 2.1 を勉強中の身で、すべての項目にわたってきちんと理解しているとはとてもいえない。したがって、誤りも多く含まれると思うので、その点を留意してほしい。逆に間違っている場所を教えていただけると助かります。ただ、CSS 2.1 はあまりに複雑で、そのままでは頭に入らないので、「なぜこのルールは存在するのか?」ということを常に考えながら勉強していこうと思っている。これからの文章で「このルールってこういう趣旨だよな〜」とかブツブツ言っているかもしれないが、読みたい人は読めばよし、読みたくなければスルーしてほしい。

用語定義

本論を始める前に。CSS(Cascade Style Sheet)の状態はハッシュと同様、プロパティ(キー)と値の組み合わせによって表現される。ただ曲者なのが、同じプロパティの値にも何種類か存在するということ。(CSS21:6.1 Specified, computed, and actual values) その中で代表的なのが指定値(specified value)と計算値(computed value)である。*.css といったスタイルシートファイルに書く値は、指定値になる。指定値をユーザーエージェント(ブラウザ)の環境で評価した値が、計算値になる。

記法

  • たとえば「CSS 2.1 の 9.7 章」を "CSS21:9.7" と短縮表記する。
  • CSS において、たとえば display プロパティの値が block のとき、"display:block" のように表現することがある。

本論

CSS21:9.7 Relationships between 'display', 'position', and 'float' は display, position, float の関係について規定している。

プロパティ display, position, float には任意の値を指定しうる(指定値)。その中のいくつかの値の組み合わせだけが、実際に意味を持ちうる。であるから、display, position, float の値の組み合わせに基づいて、実際に使用される値が計算される(計算値)。下表は、それぞれのプロパティが取りうる値集合を示している。

プロパティ 値集合
display none, block, inline
position static, relative, absolute
float none, right, left

*1

以下では、display, position, float の指定値から計算値を導出するアルゴリズムについて考える。

このアルゴリズムは、実際に CSS21:9.7 に定義されているものの簡略版である。CSS は複雑すぎて、あまり細部にこだわるとすぐ大筋を見失ってしまう。だから、ここはあえて不正確さを恐れずに述べてみる。

図は、CSS21:9.7 のアルゴリズムフローチャートで表現したものである。*2


ただし、このアルゴリズムを考える上では、position の static と relative, float の right と left はそれぞれ同じように振舞うので、くくって考える。A or B を "A|B" のように表現する。

いま手元に1つ要素があると考えよう。display:none のときは、この要素にかかわる描画はいっさい行われない(処理A)。 完全に無視可能なので、この場合はここでは考えないことにする。

条件分岐2から下をよくよく見ると、display:inline という計算値を持つには、指定値が display:inline, position:static|relative, float:none というパタンしかないことがわかる。
それ以外の場合は, display:block(計算値)になる。

position:absolute(指定値)のときは、かならず float:none(計算値)となる。逆にいうと float:right|left(計算値)の時は、position: absolute(指定値)ではない。

こうやってみるとこのアルゴリズムで、指定値と計算値が異なりうるのは、display と float だけだとわかる。position は決して変化しない。

考察の結果をまとめてみる。

display positionfloatdisplay position float
block static|relative none block static|relative none
block static|relative right|left block static|relative right|left
block absolute none block absolute none
block absolute right|left block absolute none
inline static|relative none inline static|relative none
inline static|relative right|left block static|relative right|left
inline absolute none block absolute none
inline absolute right|left block absolute none

表の左側が指定値(緑)右側が計算値(青)を表現している。表の中で黄色で表現されているセルは指定値と計算値が異なるものである。

いろいろ考えてきたが、結局、計算値ベースでは以下の4通りの組み合わせしかないということだ。

display position float
block static|relative none
block static|relative right|left
block absolute none
inline static|relative none

なるほどねえ。興味深い。私的にはかなり頭がすっきりした。

*1:position:fixed というのがあるが、割愛した。今回のアルゴリズム上は、absolute を fixed と読み替えてもかまわない。

*2:注: B. の処理ボックスにおいて、display = block とあるが、この規定は実際には CSS21:9.7 にはない。だが、display:inline な要素に position:absolute を指定すると、スタイルの left, top で位置を指定し、width, height で大きさ(dimensition)を指定することができるようになる。ブロックレベル要素と同じ振る舞いをもつようになるので、計算値が display:block になったと考えて、このように記述した。実際 FireFox 2.0 では display の計算値は "block" になっている。(しかし恐ろしいことに IE6 では計算値は "inline" のままだ)