CSSでレイアウトするなら絶対覚えておきたい配置のルール:フロートや絶対配置、z-index とかいろいろ

Posted under - Web Design

116

最近改めて CSS の基本、要素の配置、レイアウトについて学習しました。過去に CSS でのレイアウトなどの記事を書いた事があるんですけど、改めて勉強してみたら、いろいろ間違えて解釈していたなー ... っていうか、基本が分かってなかったんだなーと反省 ...。今回は CSS の基本中の基本、視覚整形モデルについてまとめてみました。

CSS VISUAL FORMATING MODEL
Webデザインをする上で、必須とも言えるのが CSS …。このブログ – Webデザインレシピでも、過去に CSS について書いた記事がいくつかあります。最近 … でもないけど、以下のふたつは CSS でのレイアウトについて、いろいろと書いた記事でした。

でもこの記事を書いた後、ツイッターなどでちらほら下のようなご意見を頂きました。

  • 「CSSの仕様書を読んだ方がいいよー!」
  • 「気になる点がいくつかあった」
  • 「なんかちょっと違うなー」… などなど …

でも当時の私には、何処が間違っているのか分からなくて、まわりの友達に聞いたりしても解決にはいたりませんでした …。そこであれから自分なりに色々勉強してみました。そして今では少しだけれど、どうして仕様書を読んだ方がいいのか、何処が間違っていたのか … という事が分かってきました。

なのでこの記事では、過去の記事での間違いを訂正する意味も込めて、改めて CSS でのレイアウト作りに関する事 … 本当に基本的なことをまとめてみました。そして、過去記事で間違った解釈で説明していたこと … ごめんなさい。まちがえてました。この記事の公開と同時に、過去記事内の間違った記述も訂正させていただければと思います。

また、この記事は CSS でレイアウトを組む為の基本についての記事です。ボックスモデルから始まって、通常フローフロート相対配置絶対配置、それから重なりを指定する z-index までを、私なりに仕様書や書籍、色んな Webサイトを参考にしてまとめたものです。なので真新しい事は何も書いていません …。でも、もし私のように誤解したまま(というか、曖昧な理解のまま)CSS の記述をしている人がいたなら、参考にしてもらえたらなーと思ってまとめてみました。

そして間違いに気付かせてくれたみなさん、ツイッターなどでつぶやいてくれたみなさん、本当にありがとうございました!

CSS 視覚整形モデル 目次

  1. CSS の基本中の基本 ボックスモデル
  2. 包含ブロックとは
  3. ボックスの配置その1 通常フロー
  4. マージンの相殺が起こる場所
  5. ボックスの配置その2 フロート
  6. clear プロパティーとは
  1. フロートをもっと理解しよう
  2. ボックスの配置その3 相対配置 position:relative
  3. ボックスの配置その4 絶対配置 position:absolute
  4. ボックスの配置その5 固定配置 position: fixed
  5. ボックスの配置その6 重なり順は z-index で指定しよう!

1. CSS の基本中の基本 ボックスモデル

まずは基本中の基本、CSS でのボックスモデルからおさらいです。とっても今更なんですけど、CSS でのレイアウト作りをする上で、これが基本になっています。なのでやっぱりここから紹介していきますね!

CSS では、各要素が生成する四角い領域のことを、ボックスモデルと呼んでいます。各要素が生成する四角形の領域 … これはブロックレベル要素に限りません。インライン要素にだってボックスが作られています。例えばインライン要素である a要素にボーダーを指定してあげれば、やっぱり四角い線が引かれますよね!そこに四角いボックスモデルがあるからなんですよね。

インライン要素にだってボックスがある

a要素にボーダーを指定してみた。

そしてボックスモデルは以下の要素で構成されています。

  • 内容(コンテンツ)
  • ボーダー(border)
  • 内容とボーダーの間の余白(padding)
  • ボーダーと他のボックスとの間の余白(margin)

Webデザイン – CSS を学んだ人なら、もう何度も目にしていると思いますが、ボックスモデルを図にすると以下のようになります。

ボックスモデル

ボックスモデル

また、要素に指定した背景は、ボーダーの内側に敷きつめられ、マージンの領域には指定できませんよね!上の図を見ると、まるでブロックレベル要素の事を説明しているみたいですけど、インライン要素だってこの図に当てはまります。インライン要素の場合は、上下のマージンは効きませんが、基本的には同じですね!まずはこのボックスモデルを、しっかり頭に入れておきましょう!

2. 包含ブロックとは

ボックスモデルの次は、包含ブロックについて見ていきます。包含ブロック … 少し難しい言葉ですねー。さっきのボックスモデルでできたボックス … このボックスの配置包含ブロック(コンテナブロック)というものによって決められます。

包含(ほうがん)ブロック … 最初読めませんでした … X(

包含ブロック … ちょっと言葉では難しいので、図を使って説明しますね!まずは以下の HTML で考えてみます!

HTML
<div>
<p>
こんにちは!
</p>
</div>
div要素によって作られた包含ブロック

包含ブロック

さっきのボックスモデルの図と似ていますけど、ちょっと違います。

さっきのボックスモデルの図と似ていますけど、ちょっと違います。

上記の図 … 子要素である p 要素の配置場所大きさって、何によって決まってるんでしょう?

答えは簡単ですね!位置は親要素である div のパディングの内側に配置されますよねー。そして p 要素の幅も、親要素である div のパディングの内側いっぱいに広がります(width を指定していない場合のお話です)。

2.1. 子孫要素の位置と大きさは、包含ブロックが決めています

こんな風に見てみると、p 要素の配置場所や大きさは、p 要素自身ではなくて、div 要素が決めている事になります。上の図で言うと、斜線の部分ですねー!この部分をdivが作り出した包含ブロック(コンテナブロック)と言います。

包含ブロックとは、子孫要素を配置する事ができる領域のこと。逆の言い方をすれば、ある要素の配置場所や大きさは、祖先の要素が作り出した包含ブロックによって決まる … ということですね!包含ブロックは、パディングがある場合はパディングの内側、無い場合はボーダーの内側 … と一致します。

このことは、感覚的に分かっていた事ですけど、この包含ブロックという言葉 … 実はとっても大事なんです。この後、色んな配置ルールを見ていきますけど、何度もこの包含ブロックという言葉が出てきます。なので、ここでしっかり覚えておきましょう!

MEMO

包含ブロックが、子孫要素の大きさを決めている … と書いてありますが、その要素自身に width を指定してない場合です。

2.2. 包含ブロックは、必ずしも親要素が作るとは限らない

上記の図では、p 要素の直近の親要素である div 要素によって、包含ブロックが作られていましたよねー。でも包含ブロックは、必ずしも直近の祖先要素によって作られる … という訳ではありません。

例えば 固定配置、position: fixed を指定した場合は、ウインドウが包含ブロックになりますし、position: absolute を指定した場合は、position: static 以外の直近の祖先要素が包含ブロックを作る事になります(これらは後述しますねー!)。position プロパティーについては後述しますが、包含ブロックは必ずしも親要素が作るとは限らないということを覚えておきましょー!

CHECK POINT

  • 子孫要素の位置と大きさは、包含ブロックが決めています!

2.3. 包含ブロック内で配置されるボックスの種類

さて、今度は包含ブロックの中で配置される側のボックスのお話です。包含ブロックの中で配置されるボックスは、大きく分けるとブロックボックスインラインボックスのふたつに分けられます。

ブロックボックスと、インラインボックス … これはもうピンときますね!包含ブロックの中で、ブロックレベル要素は自動的にブロックボックスを生成し、インライン要素はインラインボックスというものを生成します。

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

同じボックスという名前が付いてますが、その性質が違うのはご存知の通りです。ブロックボックスは、「独立したかたまり」として、どんどん下にレイアウトされていきますよね。それに対してインラインボックスは「行内の一部」として配置されていきます…。(すごい当たり前の事を言ってますね … わざわざ記事にする必要があるのかしら … と思ってきました w)でも、まずはコレが基本形ですよね!

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

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

2.4. 補足:匿名ボックスとは

上記ではブロックレベル要素が作るブロックボックスと、インライン要素が作るインラインボックスというものを見てきました。でも HTML のマークアップによっては、特に要素を指定していない部分もあるはずです。要素を指定していない部分 … ちょっと下のマークアップを見てくださいね!

HTML
<div>
<p>これは p要素の中にあります。</p>
これは div要素の直下にあります。
</div>

こんな場合の時は、ブロックボックス(p 要素の部分)とインラインボックス(テキストの部分)が混在している … というわけではないそうです。「これは div の直下にあります。」のテキストの部分は、匿名ブロックボックスというボックスが自動的に作られているんだそうです。

図にするとこんな感じ…。

匿名ブロックボックス

匿名ブロックボックス

インラインボックスの場合も、同じように匿名インラインボックスというものが作られています。

HTML
<p>
ここは普通のテキストです。<em>ここはem要素です。</em>ここは普通のテキストです。
</p>
匿名インラインボックス

匿名インラインボックス

2.5. ブロックレベル要素とブロックボックス

さっきのブロックボックスのところとちょっと重複しますけど、大事な所なのでもう一回 …。

ブロックレベルとは、「独立したかたまり」という意味。ブロックレベル要素には、見出しを表す h1 ~ h6 要素や、段落を表す p 要素など、たくさんの要素がありますね!そのブロックレベル要素は、前述したとおりブロックボックスを自動的に生成して、独立したかたまりとしてどんどん下にレイアウトされていきます。

見出しを並べた例

ブロックボックスは下にレイアウトされていきます。

ブロックボックスは、たとえボックスの幅が小さくても、基本的に横に並ぶ事はありません …。上記の見出しは、長いもの、短いものそれぞれですが、通常のレイアウトのフロー(フローについては後述しますね!)によって、どんどん下にレイアウトされていきます。

2.6. インライン要素とインラインボックス

それでは今度はインライン要素を見てみましょう。インラインは「行内の一部」という意味。インライン要素には a 要素や strong 要素、img 要素などがありますね!そしてインライン要素は、自動的にインラインボックスを生成します。

インラインボックスは行内の一部なので、続けてかいても横にレイアウトされていきます。レイアウトという言い方はおかしいかもしれません … あくまで行内の一部として扱われます。インライン … テキストレベルという覚え方をした方が、分かりやすいかもしれません。

HTML
<p><a href="#">これは a要素</a>、
<em>これは em要素</em>、
<strong>これは strong要素</strong>
</p>
インラインボックス

これは a要素これは em要素これは strong要素

2.7. displayプロパティ

ここで(やっと)display プロパティーの登場です!display プロパティーは、ご存知の通り要素の表示方法を指定するプロパティ。インライン要素に display: block を指定すれば、ブロックボックスとして表示してくれます。

逆にブロックレベル要素に display: inline を指定すれば、インラインボックスとして表示してくれます。(display プロパティーには他にも値があります … display: inline-block とか …。でもちょっと長くなりそうなので、今回は割愛しますね!)

例えばインライン要素をブロックボックスとして表示すれば、widthheight も指定できるようになりますし、上下のマージンも指定できるようになりますよね!下はもともとインライン要素である a 要素を display: block でブロックボックスにした例 … ただのリンクをボタン風にする事だってできますよね!

a要素をボタン風に …

Sample

1. 補足:ちょっと変わったインライン要素

インラインボックスを生成するインライン要素。その性質として、widthheight、上下の margin は指定できませんでした。でも img 要素や、input 要素、textarea 要素など、HTML で widthsizecolsなど、大きさに関する属性を指定できる要素は、この限りではありません。

CHECK POINT

  • ブロックボックスは「独立したひとかたまり」
  • インラインボックスは「行内の一部」

3. ボックスの配置その1 通常フロー

ボックスモデルに始まり、包含ブロック、ブロックボックスやインラインボックスなどを見てきました。それでは実際にデザインをレイアウトするための、ボックスの配置について詳しく見ていきましょう。

ボックスの配置には、float プロパティposition プロパティ、そして重なりをコントロールする z-index プロパティーを使いますよね。でもその前に、通常の配置(position: static のこと)での配置をおさらいします。

3.1. 通常フローとは?

まず通常フローとは何でしょう?フローという表現が分かり難いかもしれませんが、流れ … 川の流れみたいなもの(あくまでイメージです)。この流れの上に、各要素が乗っかって、レイアウトとして配置されていくんですねー。

そしてこのフローには、ブロックボックスが属する流れ(ブロックボックス整形文脈)とインラインボックスが属する流れ(インラインボックス整形文脈)のふたつがあります。

1. ブロックボックス整形文脈

ブロックボックス整形文脈 … 言葉は難しそうですが、ブロックボックスが属する流れのこと。この流れの中でブロックボックスは、上から下へどんどん配置されていきます。さっき見出しを例にして見てきましたね!言葉は難しそうですけど、内容はとっても簡単です。

そういえばさっき匿名ブロックボックスというのがありましたね!覚えてますか?さっき、なんで匿名ブロックボックスというものが必要なのかなー?と思った人もいるかもしれませんが、このブロックボックス整形文脈の流れに乗せる為に、匿名ブロックボックスが必要だったんですねー。

この流れ、ブロックボックス整形文脈の中では、ブロックボックスの左外辺(マージンがある場合は マージンの左辺)が、包含ブロックの左外辺にくっつく形で配置されます。すでにコーディングに慣れてる人にとっては、当たり前といえば当たり前ですねー。通常フローの中では、包含ブロックは基本親要素になりますから、親要素の左端に接する形で配置されますよね!

そして上下の間隔はマージンによって決まります。ここで気をつけなくてはいけないのがマージンの相殺です …。マージンの相殺については、ちょっと後で詳しく書きます。

2. インライン整形文脈

ブロックレベル整形文脈は、ブロックボックスを配置するフローでした。それに対してインライン整形文脈は、インラインボックスを配置する流れです。インラインボックスは包含ブロックの上から、横方向に並べられていきます。

これも簡単ですねー!インラインボックスは行内の一部ですから、とても自然な流れで理解しやすいと思います。

また、インラインボックス(匿名インラインボックスも含みます。)は横に並んでいきますが、いわゆる一行という単位で行ボックスという四角い領域も作られています。

行ボックス

行ボックス

行ボックスは、基本的に包含ボックスの幅いっぱいに広がります。でも間にフロートした要素がある場合に、幅が狭くなる場合があります。ん?間にフロートが入る場合って? … それはこの後のフロートのところで詳しく説明しますねー!

CHECK POINT

  • CSSには、通常フローという流れがある。
  • ブロックボックスはブロックボックス整形文脈に属して、インラインボックスはインライン整形文脈に属します。

4. マージンの相殺が起こる場所

さて、ブロックボックス整形文脈のところで、マージンの相殺という言葉が出てきました。マージンの相殺は、上下に隣り合っている同士のボックスの間と、入れ子関係にあるボックスの間で起こります。左右に隣り合っている場合は相殺されません。

入れ子関係のときの場合は、ボーダーやパディングがお互いのマージンの間にない場合に限り、マージンの相殺が起こります。ちょっと図を使って説明しますね!

4.1. マージンの相殺:上下に隣り合ってる場合

マージンの相殺

上のボックス 1には margin-bottom: 50px が指定してあります。そして下のボックス 2には margin-top: 30px が指定してあります。このような場合、マージンは足して 80px になる訳ではなくて、相殺されて大きい方の 50pxになるんですねー。これは上下にとなり合ってるボックス同士の場合です。横に並んでるときは相殺しません。

それではもうひとつの例を見てみます。今度の場合は、入れ子関係にあるときのマージンの相殺です。

4.2. マージンの相殺:入れ子関係の場合

入れ子状態のマージンの相殺

何だかこんがらがってきましたねー … さっきは上下に隣り合ったマージンは相殺されるって言ってたのに、上の図では相殺されずに足し算されてるようにも見えます…。 でも、20px と 30px を足しても 50px だし … 少し整理してみましょう。

まず、上のボックス 1と下のボックス 2間のマージンは、相殺されて 30px になります。これは例 1の時と同じですね!間違いありません。ではなぜふたつのボックスの間が 60px になってしまうのでしょう?これはまた別の所でマージンの相殺が起こっているからなんです。

それが前述した「入れ子関係時の場合は、borderpadding がお互いのマージンの間にない場合にマージンの相殺が起こります。」の部分 … つまり、下の div 要素 2 2と、その中に入っている h2 要素 3の間でもマージンの相殺が起こっているんですねー。

div 要素2 2には paddingborder も指定していませんし、h2 要素 3も同様です。つまりこのふたつの要素のマージンは、接し合ってる状態なんですねー。そこで相殺してしまうと … まるで div 要素の margin-top が 60px であるかのようになってしまうんです!

下の図は、ブラウザで見たときの感じです …。

入れ子状態でのマージンの相殺

ブラウザでの表示

div 要素2 に内包されている h2 要素 3に指定したマージンが、まるで div 要素2 2を突き抜けて、上の div 要素1 1と相殺している感じに見えますねー。

h2要素 3に指定したマージンを、下の div要素2 2との間に設定したい場合には … 間にパディングを入れたり、ボーダーを入れたりすれば OK ということでしたね!

間にボーダーを入れると、マージンの相殺はしない

ボーダーを指定した場合

というわけで、下の div要素2 2にボーダーを指定してみました。こうすると、h2要素 3との間でマージンの相殺は起こらないで、ちゃんと余白ができました!

また、ボーダーやパディングを指定しなくても、下の div要素 2overflow: hidden; を指定することでも、マージンの相殺を回避することができます。

4.3. フロートさせるとマージンの相殺は起こりません

さて、マージンの相殺を見てきましたが、これはあくまで通常フロー内でのお話です。例えば下側の div要素2 2をフロートさせると、マージンは相殺されなくなります。

div をフロートさせた場合

フロートさせるとマージンの相殺はしません

フロートさせた要素は、通常フロー(流れ)から外されて、新たなフローを作る …つまり同一上の流れの中に入ってないんですねー。なので相殺されないで、ちゃんとマージンが足し算されています。

さて、通常のフロー(position: static)での配置を見てきました。改めておさらいしても、特に難しい事は無かったと思います …。でもここで登場した、通常フロー行ボックスという言葉は、フロートや相対配置、絶対配置などのところでも登場します。またマージンの相殺についてもキチンと押さえておきたいですね!

それではいよいよ通常の通常フロー以外の配置、まずはフロートについて見ていきましょう。

CHECK POINT

  • 上下に隣り合ってる要素通しには、マージンの相殺が起こります。
  • 入れ子関係にある場合も、マージンの相殺が起こる場合があります。
  • フロートした要素のマージンは相殺されません。

5. ボックスの配置その2 フロート

フロート … CSSでレイアウトを組んでいくときに、誰もが使っていると思います。フロートは要素を左、または右に寄せてくれる便利なプロパティ。でもフロートは、それ自身だけでなく他の要素へも影響してしまいます。正しく使わないと、カラム落ちやレイアウト崩れを起こしてしまいますよね。

ここではフロート自体の性質と、他の要素に与える影響などを見てみましょう。そうする事によって、なぜレイアウトが思うように組めないのか … などが見えてくると思います。基本がわかれば、解決策を見つけるのも早くなるかもしれませんね!

5.1. フロートとは?

結局のところ、フロートって何なんでしょう?

MEMO

フロートとは、要素のボックスを通常フローから取り外し、左、または右に移動させること。浮動化ともいいます。そしてフロートさせたボックスには、width を指定しなくてはいけません。でも、width 属性を指定してある img 要素や、size 属性を指定してある select 要素など、大きさがはっきり分かるものは、width プロパティーを指定しなくても OK です。

また、通常フローの中のインラインボックスには、width を指定しても有効になりませんでしたが、インラインボックスはフロートさせるとブロックボックスになるため、width を指定できるようになります!

実際には width を指定しなくても、内包する要素の幅にフィットします … でも決まりなのでしっかり width を指定するようにしましょう!

さて、それでは実際に要素をフロートさせてみます。float プロパティーで指定できるのは、以下の3つですね!

  1. float: left;
  2. float: right;
  3. float: none;

none はフロートさせないという事なので、ここでは float: left を例に見てみましょう。float: right は左右が入れ替わるだけなので、左を右と読み変えてください。

float: left

左に寄せられたブロックボックスを生成します。後に続く要素は、そのブロックボックスの上辺から右側に回り込みます。

ちょっと難しい言い回しですねー。とにかく float: left を指定すると、インライン要素もブロックボックスを生成して、左側によせられます。そして後に続く要素にも影響を与えます。フロートの後に続く要素は、右側に回り込むんですねー。

フロートの例

フロートに続く要素は右側に回り込む

HTML
<p>
<img src="image.jpg"  alt="" />
フロートとは ...
</p>
CSS
img{
    width: 200px;
    float: left;
}

これが基本です。なんだ … 簡単じゃない!って思うかもしれません … でも、フロートには厳格な配置ルールというものがあるので、もう少し見てきましょう。それが以下の 10項目です。

5.2. フロートの厳格な配置ルール

ちょっと長いですけど …。

  1. 左にフロートされたボックスの左外辺(マージンがある場合はマージンの左辺)が、包含ブロックの左辺より左側にあってはならない。同じ事が右にフロートされたボックスにも当てはまる。
    つまり包含ブロックからははみ出ないということですねー。
  2. 左にフロートされたボックスの後ろに、別の左にフロートさせたボックスがある場合、後ろのボックスは前のボックスの右側に配置されるか、下に配置されなければならない。同じ事が右にフロートされたボックスにも当てはまる。
    (これは右に空いてるスペースによりますね!収まりきれれば右側に、収まりきれなければカラム落ちのような状態になりますよ!ということですねー。)
  3. 左にフロートされたボックスの右外辺(マージンがある場合はマージンの右辺)が、右側にフロートされたボックスの左外辺より右にあってはならない。同じ事が右にフロートされたボックスにも当てはまる。
    (言い回しが難しいですけど、フロートしたボックス同士は重ならないって事ですね!)
  4. フロートされたボックスの上外辺は、包含ブロックの上辺より上にあってはならない。
    (これは簡単ですねー!包含ブロックからははみ出ません。)
  5. フロートされたボックスの上外辺(マージンがある場合はマージンの上辺)は、それ以前の要素が生成したブロックボックス、またはフロートボックスの上外辺より上にあってはならない。
    (2カラムレイアウトを例に考えると分かりやすいですねー!2番目にフロートしたボックスが、先にフロートしたボックスの上辺より上にくることはありません。)
  6. フロートされたボックスの上外辺(マージンがある場合はマージンの上辺)は、それ以前の要素が生成したボックス内の行ボックスの上辺より上にあってはならない。
    (これもさっきと同じように2カラムレイアウトで考えれば納得ですね!)
  7. 左にフロートされたボックスの後に、別に左にフロートされたボックスがある場合、後ろのボックスの右外辺が包含ブロックの右辺より右にあってはならない。同じ事が右にフロートされたボックスにも当てはまる。
    (これも簡単、包含ブロックからははみ出ません。その結果、幅が入りきらなければ下にレイアウトされますよね!)
  8. フロートされたボックスは出来る限り上に配置されなければならない。
    (余分な空白はできずに、可能な限り上に配置されますよね!)
  9. 左にフロートされたボックスは、出来る限り左側に。右にフロートされたボックスは、出来る限り右側に配置されなければならない。また、後に続くフロートされたボックスよりも、優先的に上方に配置されます。
    (優先的に上方に … という部分は、もしカラム落ちするのであれば、後から配置された方が下に配置されて、先に配置された方が上に配置される … ということですね!)
  10. フロートされたボックスに clear プロパティーが適用される場合、そのボックスの上辺は、「clear:left」の場合はそれ以前の全ての左にフロートされたボックスの、「clear:right」の場合はそれ以前の全ての右にフロートされたボックスの、「clear:both」の場合は左右両方にフロートされたボックスの下外辺よりも下に配置されなければならない。
    (ちょっと長いですけど … clear したボックスは、フロートしたボックスよりも下に配置されるってことですね!)

Web標準の教科書―XHTMLとCSSでつくる“正しい”Webサイト より
リンクはアマゾンに飛びます。

さて、厳格な配置ルールといっても、感覚的に理解できる感じですねー。特に難しい所はないように思います …。

ここでちょっとクイズです。フロートの厳格ルールを踏まえて、下のコードがどんな風にブラウザで表示されるか考えてみてください。画像に float: left を指定しています。その画像よりも前に、1行だけインライン要素(strong)があります。

HTML
<body>
<p>
<strong>今日はフロートについて勉強しました。</strong>
<img src="image.jpg" alt="" />フロートとは ...
</p>
</body>
CSS
img{
    width:200px;
    float:left;
}

実はこんな風に表示されます。

上記のコードの表示

画像の右側に配置されてる ...

上記のルールをもう一度読み返してみてください。画像より上に 1行目がくるのでは? … と思った人も、決して間違いではありません。

8番のルールでは、フロートはできるだけ上方に配置される … とありましたね!上記の場合は、p 要素が作る包含ボックスの幅に余裕がある為に、こんな風に表示されます。

では、包含ボックスの大きさに余裕がなくなったら?試しに p 要素の幅を小さくしてみると …

p要素の幅を小さくした場合

画像より上に配置された

太字の部分と写真の幅 … 両方の幅の合計よりも p 要素の幅が小さい場合は、上記のように表示されます。いわゆるカラム落ちと同じような状況になるんですね!そして残りのテキストは、そのまま右側に流し込まれます。

ちょっといじわるなクイズでしたけど、コーディングしていて思うようなレイアウトで表示されないときは、この厳格ルールを思い出して、ひとつひとつチェックしてみるといいかもしれませんね!

CHECK POINT

  • フロートさせたら、width も一緒に指定する。
  • インラインボックスはフロートさせるとブロックボックスになる。
  • フロートは、通常フローから外れます。

6. clear プロパティーとは

フロートを解除するときは、clear プロパティーを使いますよね!clear プロパティーは、横に配置するという流れを止めて、フロートの下に配置させる為のプロパティーです。ご存知の通り、以下の三種類の値がありますよね!

  1. clear: both;
  2. clear: left;
  3. clear: right;

さて、それでは実際によく使われているレイアウト、2カラムレイアウトを作って、clear プロパティーを試してみましょう。

HTML
<div id="container">
    <div id="header"> ... </div>
    <div id="main"> ... </div>
    <div id="sidebar"> ... </div>
    <div id="footer"> ... </div>
</div>
ブラウザでの表示

ブラウザでの表示

いろいろ余計なプロパティーも書かれていますが … まずは左カラム 2、右カラム 3を見てみましょう。両方 float: left が指定してあります。右カラムは float: right じゃないの?って声も聞こえてきますが、今回は float: left を指定してみました。

float: left

左に寄せられたブロックボックスを生成します。そして後に続く要素は、そのブロックボックスの上辺から右側に回り込みます。

という訳なので、別に float: right じゃなくても OK なんですねー。後に続く要素(右カラム)が、ちゃんと右側に回り込んでいますね!

6.1. clear プロパティーはブロックレベル要素に指定する

次に footer(フッター) を見てみましょう。左カラムも右カラムも float: left で配置してあるので、clear: left でボックスを下に配置しています。clear プロパティー … フロートの厳格な配置ルールの 10番で見た通りですね!。ボックスをフロートの下に配置してくれます。でもちょっと注意しなくちゃならない事もあるんですねー。

clear プロパティーはブロックレベル要素に指定する

そうなんです … X( clear プロパティーは、ブロックレベル要素にしか指定してはいけないプロパティーなんです。CSS1 の頃は、インライン要素にも指定する事ができましたが、CSS2 からは指定できなくなりました…。

よくインライン要素である br 要素に、指定したりしていましたが、CSS2 の仕様ではダメみたいですねー。でもー!… 文法エラーにはならないようです …。

6.2. clear を指定した要素の margin-top が効かない?

上の図を見てみると、clear を指定した footer に margin-top: 20px を指定してあります。でも実際には余白が無くて、マージンが効いていないように見えます …。ここでもう一度、フロートの厳格な配置ルールの 10番を見てみましょう。

10. フロートされたボックスの下外辺よりも下に配置されなければならない。

このルールによって、clear した footer には自動的に余白が追加されています。ん?余白が追加されるっていっても、余白が無いから困ってるんじゃない … これは一体どういうことでしょう? ちょっと整理してみましょう。

追加された余白(クリアランス)

クリアランスが追加される

まず、フロートされたボックスは、通常フローから外されます。なので本来なら、footer は header のすぐ下に配置されるはずです(通常フローで考えてくださいね!)。でもフロートの厳格ルールの 10番によって、フロートの下に配置されなければなりませんよね。そのために、クリアランスという余白が自動的に追加されているんです。

ですから、margin-top はフロートボックスとの余白に対してのものではなく、通常フロー同士のヘッダーとフッターの間の余白に対してのものなんです。なので … たとえばフロートボックスよりも高いマージンを指定すれば、キチンとマージンが効く事を確認できます。

マージントップを大きくしてみると …

マージンを大きくした場合

フッターのマージンを 300pxに指定しました。

でも、実際にはこんな風に指定することはありませんよね!フッターとフロートボックスの間に余白を作りたい場合は、フロートしたボックス(#main#sidebar)に margin-bottom を指定すれば OK です。フロートしたボックスのマージンは相殺されませんから、margin-bottom: 20 px とすれば、20px 分の余白ができます。

そう … フロートした要素のマージンは相殺されません。なので上記の図の中、ヘッダー(margin-bottom: 20px) と フロートボックス(margin-top: 20px)の間の余白は、相殺されずに 40pxの余白ができているんですね!実際にはこんな風に指定する事は無いかもしれませんが、覚えておくといいかもです!

CHECK POINT

  • clear プロパティーはブロックレベル要素に指定しよう!
  • clear した要素には、クリアランスが自動的に追加されることがあります。

7. フロートをもっと理解しよう

すこし大雑把にフロートを見てきましたが、ここからは少し整理しながら詳しく見ていきましょう。まず、絶対に覚えておきたい事。何度か出てきましたが、フロートを指定した要素は通常フロー(通常の流れ)から外れます。ということは … 一体どうなるのでしょう?ちょっと例をみてみましょう。

フロートの例1

画像が p 要素からはみ出してる ...

上記のサンプルのコードは、以下のようになっています。

HTML
<p>
<img src="image.jpg" alt="" />
フロートとは ...
</p>
<p>
フロートさせた要素には ...
</p>
CSS
img{    
    width : 200px;
    float : left;
}
p{
    padding: 10px;
    border: 1px dashed #d64e80;
    background: rgba(255,255,255,.5);
}

まず、フロートは通常フローから外されてしまいます。このサンプルでの通常フローに属している要素は、ふたつの p 要素ですね!その通常フローから、フロート(浮動化)した画像は外されている … ということです。通常フローから外されているので、きちんと上の p 要素内に収まってないのも当然なんですねー。p 要素から画像がはみ出してるのはそういう訳なんです。

逆を言えば、親要素の高さはフロートされた子要素の高さを含めない … という事が言えそうです!同じフローの中にないので、当然と言えば当然ですねー。

そして 2番目の p 要素 … これは通常フローなので、普通に 1番目の p 要素の次にブロックボックスとして配置されているんです。もし写真がなければ、以下のように表示されますよね!その状態と何も変わらないんです。

フロートした画像が無かった場合

写真がなかった場合の配置

フロートは浮動化。浮かせて動かして配置しているだけなんです。なので立体的に考えると、フロート性質が分かりやすいかもしれませんね!あれ?浮かせてるんだったら、どうして以下のように表示されないの?って思うかもしれませんね …。

こんな風に表示されないのは何で?

こんな風に重ならないのはなんでなの?

浮いてるのなら、上記のように重なって表示されないのはなぜなんでしょうか?ここでインラインボックスの所で学んだ、行ボックスを思い出してみてください。

行ボックスは、基本的に包含ボックスの幅いっぱいに広がります。でも間にフロートした要素がある場合に、幅が狭くなる場合があります。

とありました。思い出しましたか?今回のサンプルでは、間にフロートした画像が入っていますよね!なのでその分行ボックスが縮んで、以下のように表示される … という訳なんですね!

縮んだ行ボックス

本当は長いけど、縮んだ行ボックス

7.2. フロートでレイアウトを作ってみよう!

それではフロートを使って、実際にレイアウトを作ってみましょう!目指すレイアウトは以下の形です。

目標のレイアウト

目標のレイアウト

HTML は以下のようになります。

HTML
<div class="post">
<h4><a href="#">フロートでレイアウトしよう!</a></h4>
<img src="image1.jpg" alt="" />
<p>
今回はフロートを使って ...</p>
<p>
<a class="more" href="#">続きを読む »</a>
</p>
</div>

それでは CSS でレイアウトしていきましょう。

  1. まず一番外側のボックスの幅は 480px とします。
  2. 見出しである h4 要素の幅を指定して float: right で右に寄せます。幅は包含ボックスから、画像が入る分を引いて短くしておきます。
  3. 次に img 要素を float: left で 左に寄せます。見出しの width と画像の width の合計(marginpadding も含む)が、包含ボックスの幅と同じにするのがポイントです。もし隙間があると、p 要素内のテキストが流れ込んできてしまうからです。
  4. 「もっと詳しく »」のリンクを float: right で右に寄せました。
  5. float を clear するために、div要素に clear: both を指定しました …
CSS
.post{
    background:#fff;
    padding:20px;
    width:440px;
    margin-bottom:40px;
    clear:both;
    /* 以下は丸角とシャドウは省略 */
}

h4{
    width:290px;
    float: right;
}

img {
    width: 120px;
    float: left;
    padding :5px ;
    background:#fff;
    margin-right:20px; /* テキストとの距離 */
    /* 以下、丸角とシャドウは省略 */
}

.more{
    float: right;
}

すると …

ブラウザでの表示

ブラウザでの表示

惜しいです …。何度も言いますが、フロートは通常フローから外されてしまいます。その結果、通常フローである div 要素では、フロートした要素の高さを含みません …。HTML のコードをいじらずにこの問題を解決する為には、ふたつ程方法があります。(他に方法があったら、教えていただけると嬉しいです!)

7.3. overflow: hidden でフロート解除

ひとつ目は、div 要素に overflow: hidden を指定する方法です。先ほど「通常フローである div 要素では、フロートした要素の高さを含みません」と書きました。でもこれには続きがあります。

height の値が autooverflow の値が visible 以外のブロックボックスが、そのマージン下辺よりも下にくるようなフロートを子に持つ場合、その高さはフロートを含むように広げられる。

そうらしいです。

という訳で、overflow の値を visible 以外 (scroll にするとスクロールバーが出てしまうので、hidden がいいかも)にしてしまえば、キチンとフロートした要素を包んでくれるようになります。この場合には、div に指定した clear: both は不要になります。

CSS
.post{
    background:#fff;
    padding:15px;
    width:600px;
    margin-bottom:40px;
    /* clear:both; これは不要 */
    overflow : hidden;
}

でも本来 overflow: hidden は、切り抜く(はみ出す部分を隠す)プロパティーです。もし、ボックスの端ギリギリの要素に box-shadow でドロップシャドウをかけてあった場合、ドロップシャドウが隠されてしまい表示されない … ということもあるので、使用には注意も必要です。

7.4. clearfix でフロートを解除

もうひとつの方法は、clearfix という手法を使う方法です。これはご存知の人も多いと思います。

CSS
.clearfix:after {   
    visibility: hidden;
    display: block;
    font-size: 0;
    content: " ";
    clear: both;
    height: 0;
}
/* clearfix for ie7 */
.clearfix{
    display: inline-block;
}
.clearfix {
    display: block;
}

clearfix には色々なコードがありますが、基本的には :after 疑似要素と content プロパティーを使ってブロックボックスを作り、そこに clear: both を指定するという手法です。Google で clearfix と検索すれば、たくさんコードが出てきますね!

この clearfix を親要素である div 要素にしていしてあげれば、キチンとフロートボックスを内包してくれるようにまります。この場合ももちろん、div 要素の clear: both は不要です。

<h4>HTML</h4>
<div class="post clearfix">
... 省略 ...
</div>
完成

完成

今回書いた CSS のコードでは、一応 HTML に余分な装飾用のタグ(div タグ)を使わないでレイアウトすることができました。

とっても長くなってしまいましたけど、基本的なフロートの性質を見てきました。フロートを使いこなせば HTML に余計な装飾用の div 要素などを書かずに、シンプルな HTML のままレイアウトできるようになります。その為にはフロートの決まりや性質をしっかりと覚えておきたいですね!

CHACK POINT

  • clear プロパティーはブロックレベル要素に指定しましょう。
  • 行ボックスは、間にフロートした要素がある場合には幅が狭くなります。
  • 親要素の高さはフロートされた子要素の高さを含めません(overflow:hidden や clearfix を使う)。

8. ボックスの配置その3 相対配置 position:relative

フロートの次は、position プロパティーによる配置を見てみましょう。position プロパティーを使えば、通常フローでの配置からずらしたり(相対配置)、任意の場所を指定して配置したり(絶対配置)、スクロールしても常に固定されて表示される(固定配置)ようにすることができます。まずは相対配置から見ていきます。

position: relative を使えば、通常フローによって配置された位置から、ボックスを相対的にずらすことができます。相対的にずらす … これはどういう意味でしょう?いつものように図を見てみましょう!下の図は、写真とその写真のタイトルを交互に配置しています。

写真と段落を交互に表示

写真と タイトルが 交互に表示されます

HTML
<p>
<img src="image1.jpg" alt="" />
</p>
<p class="title">
画像のタイトル
</p>

<p>
<img src="image2.jpg" alt="" />
</p>
<p class="title">
画像のタイトル
</p>
CSS
img{
    width:300px;
    vertical-align: bottom;
    padding :5px;
    background:#fff;
    /* 以下、丸角とドロップシャドウは省略 */
}

.title{
    width:260px;
    background:rgba(0, 0, 0, 0.4);
    color:#fff;
    height: 40px;
    line-height:40px;
    padding: 0 20px;
}

画像には縁取り(padding と背景色)、タイトルとなる p 要素(.title)には width と背景色を指定していますが、通常フローによって、上から順番にレイアウトされていきますよね!この状態から、タイトルとなる p 要素を相対配置してずらしてみましょう。

CSS
.title{
    … 省略 …
    position:relative;
    top: -45px;
    left: 5px;
}

相対配置したい p 要素(.title)に position: relative を指定します。そして本来通常フローで配置された位置から、どれだけずらすのか(オフセットと言います)を top, bottom, left, right の各プロパティーで指定します。

上記のコードでは、top :-45px; left: 5px;としました。すると本来ある位置から、下記のようにオフセットされます!

相対配置でオフセットされたタイトル

タイトルがオフセットされました

タイトル部分が top から、-45px の位置に移動されました(上にずれました)。また、top: -45px ではなく、bottom: 45px と書いても同じように配置されます。また、左から 5px ずれて画像の枠内にピッタリ収まりました!

相対配置(position:relative)では、topbottomleftright プロパティーを使って、本来あるべき位置から相対的な距離を指定します。注意したいのは、topbottom を同時に指定することはできないし、leftright を同時に指定することはできないということ。仮に同時に指定しても、bottom よりも top が、right よりも left が優先されます。(direction プロパティ(文字の表記方向)で値を rtl(right to left) にしてある場合は逆になります。)

8.1. 相対配置したときの、後続要素への影響

position: relative で配置をオフセットした場合、後続の要素へはどんな影響があるのででょう?position: reletive によってオフセットされた要素の後続の要素は、オフセットされていない状態 … つまり通常フローでの配置を維持します。逆を言えば、オフセットされたからといって、本来あった場所に空いた余白を、詰めたりしないということ。後続の要素は、オフセットされた要素が移動前の位置にあるかのように振る舞います。

相対配置では、後続の要素の配置はそのままです

スペースはそのまま維持されます

また、position: relative を指定された要素は、通常フローの子供要素と、絶対配置される子孫要素用に、新しく包含ブロックを生成します。ちょっと難しい言い回しですね …。このことは、次の絶対配置のところで説明しますね!

CHECK POINT

  • 相対配置は後続の要素の配置に影響を与えません。
  • position: relative を指定した要素は、通常フローの子供要素と、絶対配置される子孫要素用に、新しく包含ブロックを生成します。

9. ボックスの配置その4 絶対配置 position: absolute

今度は絶対配置position: absolute)を見ていきましょう。相対配置は、通常フローでの本来あるべき場所からのオフセットでした。それに対して絶対配置は、とある場所からのオフセットで位置を決めて配置します。では、とある位置とはどこでしょう?それは、positionstatic 以外の直近の祖先要素の包含ブロック(包含ブロック … 覚えてますか?)になります。

もし、positionstatic 以外の要素がなければ、body の包含ブロックになります。簡単に言えば、position に absolute か relative が指定されている、直近の祖先要素の包含ボックスって事ですね!

でも、この包含ボックスは、従来の包含ボックスとはちょっと違います。というのも、position: relative のところで前述したとおり、position:relative を指定された要素は、通常フローの子供要素と、絶対配置される子孫要素用に、新しく包含ブロックを生成します。」ということでした。つまり、絶対配置用に新しく作られた包含ボックスとう事になります。ちょっと難しいですね …。言葉だと難しいので、図を使って見ていきましょう。

目指すレイアウトは以下の形。画像部分に、position: absolute を使ってみましょう!

目標のレイアウト

目標とするレイアウト

HTML
<div class="post">
<h4><a href="#">絶対配置でレイアウトしよう!</a></h4>
<img class="eyecatch" src="image.jpg" alt="" />
<p>絶対配置を使って ...</p>
<p><a class="more" href="#">続きを読む »</a></p>
</div>

上から見出し、画像、段落という順番でマークアップしています。まずは通常フローでの配置を見てみましょう!

通常フローでのレイアウト

通常フローでのレイアウト

HTML で記述されている順番とおり、上から見出し、画像、段落 … という順番で並んでいます。この場合、親要素である div.post が生成している包含ボックスは、padding の内側になりますよね!

通常フローでの包含ブロック

div の padding の内側が包含ブロック

それでは、div 要素に position: relative を指定して、画像に position: absolute を指定してみましょう。(この時の position: relative は、相対配置するのが目的ではなく、新しい包含ボックスを作るために指定します。)絶対配置のオフセットの位置は、とりあえず top: 0left: 0 とします。

CSS
div.post{
    width:190px;
    padding:10px;
    background:#fff;
    position:relative;    
}

img.eyecatch{
    position:absolute;
    top:0px;
    left:0px;
}

するとブラウザでの表示は以下のようになります。

ブラウザでの表示例

ブラウザでの表示

あれ … ちっちゃい X(

画像は div 要素の左上に配置されてしまいました。さらに、div 要素のボックスの高さが低くなっています …。これはどういう事でしょう?

9.1. 絶対配置されると、通常フローからは切り離される

まず、position: relative を指定した div 要素は、position: abosolute 用に新しい包含ボックスを生成しますよね!つまり通常フロー用の包含ボックスとは別に、もうひとつの包含ボックスを作るんですねー。その時の包含ボックスは、padding の内側ではなく、border の内側になります!

絶対配置用の包含ボックス

絶対配置用の包含ボックス

それでは、どうして div 要素の高さが低くなったんでしょう?それは画像を透かして見ると、よく分かります!

画像を透過してみた

画像を透かすと見出しなどが見えます

見出しや段落など、通常フローの流れに乗っている要素は、通常フローの包含ボックスの中に収まっています。そして、画像自体は通常フローから完全に切り離されて、再配置されているんです。

絶対配置された要素(画像)は、通常フローから完全に取り払われるので、後続の要素ははじめからその要素が無かったかのように振る舞います。よく、透明人間のよう … と例えられていますね!でも、実際には上記のようなレイアウトでは困ります …。そこで h4 タグに margin-top を指定して、見出しが見えるようにしましょう。

CSS
h4{
    margin-top:130px;
}
マージンなどを調整

完成

これで見出しが見れるようになりました!最後に画像の位置をちょっと調整する為に、topleft の値を指定し直しました。もしくは top: 0left: 0 のまま、margin-top: 10pxmargin-left: 10px としても OK です。absolute で絶対配置された要素のマージンは、他のどの要素のマージンとも相殺しません。

CSS
img.eyecatch{ 
  position:absolute;
  top:10px;
  left:10px;
}

「続きを読む」のリンクの部分は、普通に a要素を display: block でブロックボックス化して、text-alignright にしただけです。これで完成です!

CHECK POINT

  • 絶対配置された要素は、通常フローから完全に切り離されて再配置されます。
  • 後続の要素は、はじめから絶対配置された要素が無かったかのように振る舞います(透明人間みたい)。
  • 絶対配置された要素のマージンは、他のどの要素のマージンとも相殺しません。

10. ボックスの配置その5 固定配置 position: fixed

固定配置は、基本的に position: absolute と似ています。違う点はウインドウに対して絶対配置されるという点です。スクロールしても常に上部に固定されているヘッダーや、サイドバーなどを見た事があると思います。あれが固定配置ですねー!通常フローから取り外される点や、指定したマージンが他の要素のマージンと相殺しない点なども同じです。

11. ボックスの配置その6 重なり順は z-index で指定しよう!

いきなりですけど、z-index は、要素の重なりを指定するプロパティーです。重なり … 何ていうか、そのまんまです …。

要素の重なり

要素の重なり

普段はあまり要素同士の重なりを意識することは少ないかもしれませんが、position プロパティーで要素を本来の位置からずらした場合は、上記の図のように重なる事がありますよね!要素の重なり … 基本的には HTML で後から書いたものが上層に、先に書いたものが下層に配置されます。その重なり順を変更するのが z-index プロパティーです。

まず、この z-index は、position: static 以外を指定した要素にしか指定できません。つまり z-index を使用する要素には、position プロパティーで、relativeabsolutefixed のいずれかを指定する必要があります!

それでは詳しく z-index を見ていきましょう。ちなみに、z というアルファベットは、z 軸という意味。横方向が x 軸、縦方向が y 軸、重なりが z 軸ですね!

z-index

z-index

まず、z-index の値には整数(マイナスも指定可)か、auto を指定します。z-index を記述しなくても、 position プロパティーで relativeabsolutefixed を指定した要素には、z-index: auto が自動的に指定されます。ここでは、auto の事は一度忘れて、整数を指定してみましょう。

11.1. スタック文脈とスタックレベル

z-index で指定する整数 …。整数は大きい方が上層へ、小さい方が下層に配置されます。基本的に各要素は、スタック文脈というものに属しています。スタック文脈 … 難しそうな言葉ですねー … 以前ブロック整形文脈とか、インライン文脈とか出てきましたね!スタック文脈は、z 軸の重なりの流れ … とイメージしてもらえればいいと思います。

このスタック文脈の流れの中で、スタックレベルという数値で重なり順を決めているんですねー。z-index で指定する整数 … これがスタックレベルなんです。

記述例
  • z-index: 10;

さて、それでは上記の図1のスタックレベル … つまり重なり順を z-index で操作してみましょう。

HTML
<div id="group1">
<div id="blue1">青1</div>
<div id="blue2">青3</div>
<div id="blue3">青2</div>
</div>
CSS
#group1 { /* グループ */
    position: relative;
    z-index: 0;
}
#blue1{ /* 青1 */
   position: absolute;
    top: 40px;
    left: 40px;
    z-index: 30;
}
#blue2{ /* 青2 */
    position: absolute;
    top: 65px;
    left: 120px;
    z-index: 20;
}  
#blue3{ /* 青3 */
    position: absolute;
    top: 90px;
    left: 200px;
    z-index: 10;
}

それぞれの z-index の値、スタックレベルに注目してくださいね!

ボックスの重なり順が、z-index の値(スタックレベル)が大きい順に変更されました!スタック文脈の中で、順番が入れ替わったんですね!

重なり順が変わった!

重なり順が入れ替わります

11.2. ちょっと寄り道クリッカブルエリアと z-index

ここで少し寄り道です。上記の図の中、2番目のボックスがリンクだった場合を考えてみましょう。本来なら、ボックス全体がクリックできるはずですが、上に要素が重なっていれば、当然その部分はクリックできなくなります。

クリックできるエリア

クリックできるのは斜線の部分だけ

上記の図のように、斜線の部分だけしかクリックできません …。当然といえば、当然ですよね!ユーザーが操作する部分では、z-index の重なり順にも注意が必要ですね!

11.3. スタック文脈はひとつとは限らない

さて、それでは元に戻りましょう!もうちょっと詳しく z-index について見ていきす。今度は、同じようなグループのボックスを作って重ねてみる事にします。

違うグループを重ねる

違うグループを重なる

CSS は以下のようになっています。青いグループは一切変更してません。(top、left などは省略して記述います。)

CSS
#group1 { /* 青いグループ */
    position: relative;
    z-index:0;
}
#blue1{ /* 青1 */
    position: absolute;
    z-index: 30;
}
#blue2{ /* 青2 */
    position: absolute;
    z-index: 20;
}  
#blue3{ /* 青3 */
    position: absolute;
    z-index: 10;
}

#group2 { /* 赤いグループ */
    position: relative;
    z-index: 0;
}
#red1{ /* 赤1 */
    position: absolute;
    z-index: 35;
}
#red2{ /* 赤2 */
    position: absolute;
    z-index: 25;
}
#red3{ /* 赤3 */
    position: absolute;
    z-index: 15;
}

ここで試しに z-index の数字(スタックレベル)の大きい順に並べてみましょう。

値の大きい順
  1. 赤1 – 値 35
  2. 青1 – 値 30
  3. 赤2 – 値 25
  4. 青2 – 値 20
  1. 赤3 – 値 15
  2. 青3 – 値 10
  3. グループ1 – 値 0
  4. グループ2 – 値 0

ここでおや?っと思う人もいるかもしれません。z-index は、数字の大きいものほど上層にきて、小さいもの程下層にくると説明しました …。でも実際の順番は以下のようになっています。

実際に表示されている順番
  1. 赤1 – 値 35
  2. 赤2 – 値 25
  3. 赤3 – 値 15
  4. グループ2 … 値 0
  1. 青1 – 値 30
  2. 青2 – 値 20
  3. 青3 – 値 10
  4. グループ1 – 値 0

決して数字の大きい順に並んでいません ..。これはどういう事なんでしょう?実はここには 3つのスタック文脈が混在しているんです。… ちょっと整理してみましょう。

まず、body をルートにしたスタック文脈があり、その流れには、グループ1 1とグループ2 2が属しています。

  1. グループ1 – 値 0
  2. グループ2 – 値 0

z-index の数値、スタックレベルは同じ 0 ですね。同じスタックレベルの場合は、後から登場する要素の方が上に重ねられますから、グループ1 1の上にグループ2 2が重なっている … という訳なんです。

それから … 実は z-index の値に整数を入れると、それ自身のスタックレベルを 0 とした局所的(ローカル)なスタック文脈が自動的に作られるんです。これを局所スタック文脈と言います。そして、グループ1、グループ2の中に、それぞれ別の局所スタック文脈がある … という訳なんです。グループ1、グループ2ともに、z-index に整数「0」を指定していましたね!

グループ 1 1内の局所スタック文脈
  1. 青1 – 値 30
  2. 青2 – 値 20
  3. 青3 – 値 10
グループ 2 2内の局所スタック文脈
  1. 赤1 – 値 35
  2. 赤2 – 値 25
  3. 赤3 – 値 15

こんな風に、それぞれ別の文脈に属していたんですね!なので、それぞれの文脈の中で、きちんとスタックレベル通りに重なっていました。

もう少し見てきましょう。今度はグループ1 1 とグループ2 2の重なり順を入れ替えてみましょう。上記のサンプルでは、両方とも z-index: 0 でしたけど、今度はグループ1 1を「5」に、グループ2 2を「1」にしてみましょう。

グループの重なり順を変更

重なり順が入れ替わる

もちろん結果はこうなりますよね!でもこのままだと、実は IE7 では重なり順が変わらないんです。解決策としては、グループ1、グループ2 を内包している親要素に、position: relativez-index: 0 を明示的に指定してあげる事で解決できます。

11.4. z-index: auto が結構重要

さて、上記の例では前述した通り、3つのスタック文脈が存在しています。ここでスタック文脈を 1つにまとめてみましょう。#group1#group2z-index の値を auto にしてみます(z-index の記述そのものを消しても OK です。その場合は自動的に z-index に autoが入ります。)。整数を指定しなければ、局所スタック文脈は生成されませんから、スタック文脈はひとつになるはずですね!

CSS
#group1 { /* 青いグループ */
    position: relative;
    z-index: auto;
}
#group2 { /* 赤いグループ */
    position: relative;
    z-index: auto;
}

そのうえで、それぞれのボックスの順番を整理してみると …

青、赤が交互に重なった!

赤と青が交互になった!

こんな風に青と赤を交互に重ねる事もできるようになります!

重なり順とスタックレベル
  1. 青1 – 値 35
  2. 赤1 – 値 30
  3. 青2 – 値 25
  1. 赤2 – 値 20
  2. 青3 – 値 15
  3. 赤3 – 値 10

でも、ここには大きな落とし穴があります …。実は IE7 には、z-index: auto にバグがあるんです。z-index: auto を指定しても、IE7 ではそれ自身を「0」とした局所スタック文脈を生成してしまいます。なので上記のように、青と赤を交互に重ねる … ということは出来ないんです。これは有名なバグですが、IE7 をターゲットにしている場合は、z-index に auto を指定しても、局所スタック文脈が生成されてしまう … 結果、違う親要素間の z-index のコントロールは思うようにできない … ということだけ覚えておきましょう。

z-index の重なりは、スタック文脈という流れの中での指定です。単純にスタックレベルの高い方が上層にくる … という訳ではなく、スタック文脈がどこに存在しているか?を見極めないと混乱するばかり…。z-index をマスターするには、要素が属しているスタック文脈を把握することがポイントですね!

CHECK POINT

  • z-index の重なりは、スタック文脈という流れの中で重なっています。
  • 要素が属しているスタック文脈を把握しよう!
  • クリックしたり、ユーザーが操作する部分は最上層に配置しよう!

12. 最後に …

今回この記事を書いてみて、今までとても曖昧な理解のまま CSS を書いていたんだなーと思い知りました。包含ブロックをキチンと理解していれば、ここはパディングで余白を取った方がいいとか、こっちはマージンの方がいいとか、割とすんなり決まってきます。

それに通常フローという流れがあって、フロートや絶対配置がその流れから取り外されて、新しいフローを作る事 …。今までは、ただ横に並べるとか、そんな風にしか考えてなかったので、フローというものを意識したこともありませんでした。

Webデザイナーとして、CSS を使って仕事してきたのに、これはちょっと恥ずかしかったですねー …。いろいろと勉強になりました!過去記事についても、早いうちにメンテナンスして訂正していきたいと思います。

また、記事中ところどころで引用している部分は、私が学習に使った下記の本からのものです。リンクはアマゾンに飛びます。

Web標準の教科書

Web標準の教科書―XHTMLとCSSでつくる“正しい”Webサイト

私がこの本を買ったのは、4年程前。この本に基本的なことが書いてあったのに、全然覚えてなかったとは ….。XHTML と CSS での Web標準についての本なので HTML5 や CSS3 などの記載はありません。

また以下のサイトも参考になりました。

今回の記事は、今までで一番長い記事になってしまったかも …。最後まで読んでくれた方、本当にありがとうございました!また、この記事に書いてある事で、間違ってるよー!という事があったら、教えていただけるとうれしいです。

Comments

Thank you for the comment.