Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

  1. トップページ
  2. CSS中級編 - positionプロパティで位置を調節(2)

positionプロパティで位置を調節(2)

会社の後輩くんが
「あー、なんだよこのソース。読みづらくってしょうがねえ!」
と怒っていました。
それ書いたの3年前の貴方です。

というわけでみなさまどうもこんにちわ。

このような駄文をここまでお読み頂き誠にありがとうございました。次回が総まとめとなりますのでCSS中級編は当記事が最後となります。CSSの概要は掴めてきましたでしょうか。少しでも皆様の知力となっていれば筆者も幸いでございます。

では改めまして『position: fixed』について解説していきます。ちょっと難しい記事が続いていますが頑張っていきましょう。あ、『fixed』の読み方は『フィクスト』とか『フィクストゥ』とか『フィックスト』とかでいいかと思います。ちょっと発音が難しいですね。

『position: fixed』と指定された要素は、『position: fixed』と指定された要素はウィンドウが基準位置となり、そしてスクロールを行ってもその位置は固定されたままとなります

『top』、『bottom』、『left』、『right』プロパティを指定するとウィンドウを基準とした配置調節となりますよー、ということですね。そして『position: fixed』と指定された要素は全く違うフローのレンダリングとなるため、続く通常の要素からは存在しなかったものとしてその領域が詰まってレンダリングされます。そして『position: fixed』と指定された子要素がいる親要素は、その子要素の高さを自身の高さに算出できません。こちらは『position: absolute』と同じですね。

『position: absolute』と同じように『position: fixed』を指定された要素のマージンの相殺は起こりません。

実際にみてみましょう。縦に長いページを用意してみました。body要素に『height: 5000px』と指定しています。ついでにbody要素にはデフォルトで少しだけマージンが入ってしまうので『margin: 0』と指定し隙間をなくしています。

<div style="position: fixed; width: 100%; height: 100px; top: 0; background-color: red;">ずっと上にくっついてるよ!</div>

サンプルをみてみる。

いかがでしょうか。スクロールしても位置が変わらず表示されているのが確認できたと思います。これが『position: fixed』と指定された要素のレンダリングです。

『position: absolute』と指定された子要素は、『position: static』以外の値が設定されている祖先要素を基準として位置を調節できましたが、『position: fixed』の場合は常にウィンドウが基準として配置が決定されます。ここは間違えないようにしましょう。

さて、この『position: fixed』は固定された位置にメニューを配置したり広告を配置できたりと、その利便性は中々高いです。スマホでネットサーフィンをしているとウィンドウの下の方にずっと広告が出ているレイアウトがあったりしますよね。あれは『position: fixed』で実装されています。

あ、あと『IE6』以下のブラウザでは『position: fixed』は動かないです。昨今では『IE6』の対応を考えているところは少ないと思いますが一応覚えておいて下さい。

『position: fixed』についての解説は以上となります。続いて『z-index』プロパティについての解説を進めます。

こちらは要素の重なり具合を調節できるプロパティです。こちらのプロパティは『position』プロパティで『static』以外の値が指定されている要素に反映することができます。『top』、『bottom』、『left』、『right』プロパティと同じですね。

要素の重なり具合というのはグラフィックソフトやイラストソフトなどで『レイヤー』という概念がありますね。あれとほぼ同じです。

記述例はこんな感じになります。

div {
    position: relative;
    z-index: 100;
}
p {
    position: absolute;
    z-index: 50;
}

『z-index』にとる値は『数値』のみ、もしくは『auto』となります。『auto』と指定すると親要素と同じ階層に配置する、というわけで普通の要素の重なり方にする、という値です。各HTML要素の初期値はこの『auto』になります。なので『z-index』の値を初期値に戻したい時は『auto』と指定すればOKです。

『z-index』に数値を指定した場合は基本的にその数値が高ければ高いほど手前に表示されます。というわけでちょっと記述して実験してみましょう。

以下にサンプルを用意しました。各要素に『position: absolute』と設定し、背景色をつけて50pxずつずらして配置しています。

<div style="position: absolute; width: 100px; height: 100px; top: 50px; left: 50px; background-color: red;"></div>
<div style="position: absolute; width: 100px; height: 100px; top: 100px; left: 100px; background-color: blue;"></div>
<div style="position: absolute; width: 100px; height: 100px; top: 150px; left: 150px; background-color: purple;"></div>
<div style="position: absolute; width: 100px; height: 100px; top: 200px; left: 200px; background-color: orange;"></div>

サンプルをみてみる。

今は『z-index』を何も設定していないのでより下にいる要素が上に表示されていますね。これに『z-index』を逆順で数値が小さくなるように指定していくとこのようなレンダリングになります。

<div style="z-index: 4; position: absolute; width: 100px; height: 100px; top: 50px; left: 50px; background-color: red;"></div>
<div style="z-index: 3; position: absolute; width: 100px; height: 100px; top: 100px; left: 100px; background-color: blue;"></div>
<div style="z-index: 2; position: absolute; width: 100px; height: 100px; top: 150px; left: 150px; background-color: purple;"></div>
<div style="z-index: 1; position: absolute; width: 100px; height: 100px; top: 200px; left: 200px; background-color: orange;"></div>

サンプルをみてみる。

先ほどと重なり具合が逆になっていますね。先ほどのサンプルと見比べてみるとよくわかると思います。『z-index』を設定するとこのような感じで要素の奥行きを調節することができます。

では続いて『z-index』に同じ数値を指定したらどうなるのでしょうか。以下にサンプルを用意しました。全てのdiv要素に対して『z-index: 1』と指定しています。

<div style="z-index: 1; position: absolute; width: 100px; height: 100px; top: 50px; left: 50px; background-color: red;"></div>
<div style="z-index: 1; position: absolute; width: 100px; height: 100px; top: 100px; left: 100px; background-color: blue;"></div>
<div style="z-index: 1; position: absolute; width: 100px; height: 100px; top: 150px; left: 150px; background-color: purple;"></div>
<div style="z-index: 1; position: absolute; width: 100px; height: 100px; top: 200px; left: 200px; background-color: orange;"></div>

サンプルをみてみる。

いかがでしょうか。一番最初に『z-index』を指定していない状態での重なり方と同じになりましたね。このように『z-index』に同じ値を取ると、より下に存在する要素が手前にくるというレンダリングになります。こちらも覚えておきましょう。

というわけで『z-index』の基本的な使い方はこんな感じになります。ここまでは問題なさそうでしょうか。

続いて『z-index』のややこしい点を少しみていきましょう。この『z-index』も仕様を奥深くまでみていくとかなりややこしいプロパティになります。それをちょっと確認していきましょう。

ちなみに『z-index』は使用頻度が高いプロパティというわけではありませんのでこれから先の内容は覚えなくてもぶっちゃけ問題ないかと思います。ざっと読んでみて、面倒くさくなったらかっとばしちゃってください。

というわけで続けます。まずは以下のサンプルを確認してみてください。最初の2つのdiv要素の『z-index』の値をそれぞれ『2』『3』に設定し、その下のdiv要素に『3』と指定しています。そのdiv要素の中にさらにdiv要素を2つ用意し、その『z-index』の値は『100』、『150』と指定しました。

<div style="z-index: 2; position: absolute; width: 100px; height: 100px; top: 10px; left: 10px; background-color: red;"></div>
<div style="z-index: 3; position: absolute; width: 100px; height: 100px; top: 20px; left: 20px; background-color: blue;"></div>

<div style="position: relative; z-index: 1;">
    <div style="z-index: 100; position: absolute; width: 100px; height: 100px; top: 30px; left: 30px; background-color: purple;"></div>
    <div style="z-index: 150; position: absolute; width: 100px; height: 100px; top: 40px; left: 40px; background-color: orange;"></div>
</div>

サンプルをみてみる。

いかがでしょうか。『z-index』の値が『100』、『150』となっているdiv要素が一番手前に来そうな感じですが、実際に一番手前に来ている要素は『z-index』の値が『3』となっている青い背景色が設定されているdiv要素です。なんだか不思議なレンダリングがされていますね。

ここが『z-index』の注意点です。実は『z-index』の実態は親要素が属している『スタックコンテキスト』の中での『スタックレベル』を調整するプロパティだったりします。『スタックコンテキスト』は『スタッキングコンテキスト』、『スタック文脈』とも呼ばれてます。多分『スタックコンテキスト』が多数派です。

『スタックコンテキスト』とは各要素の奥行きの構造を形成するまとまりのようなものです。『z-index』の値に数値を指定すると自身のスタックレベルを『0』とする『スタックコンテキスト』が生成され、『z-index』の値に『auto』と設定すると親要素と同じ『スタックコンテキスト』に属し、新たな『スタックコンテキスト』が生成されることはありません。

『スタック』とはそのまま略すと『積み重ね』という意味なので『スタックレベル』は『積み重ね具合』って感じになります。この『スタックレベル』は同一の『スタックコンテキスト』内の『積み重ね具合』になります。

html要素は自動で『ルートスタックコンテキスト』というスタックコンテキストを生成しますので全ての要素は何かしらの『スタックコンテキスト』に属していることになります。『z-index』に何も指定しなかった場合は初期値の『auto』となりますので親要素の『z-index』に数値が指定されていない全ての要素は『ルートスタックコンテキスト』に属しているということになります。

そして『z-index』の値が『0』と『auto』の場合の挙動に注意です。両方共に『スタックレベル』は『0』なので挙動が似ているところもあるのですが『新たなスタックコンテキストが生成されるかされないか』という大きな違いがあります。

かなりややこしくなってきましたね。

ではちょいと最初のサンプルを思い出してみましょう。こちらですね。body要素も一緒に載せてみます。

<body>
<div style="z-index: 4; position: absolute; width: 100px; height: 100px; top: 50px; left: 50px; background-color: red;"></div>
<div style="z-index: 3; position: absolute; width: 100px; height: 100px; top: 100px; left: 100px; background-color: blue;"></div>
<div style="z-index: 2; position: absolute; width: 100px; height: 100px; top: 150px; left: 150px; background-color: purple;"></div>
<div style="z-index: 1; position: absolute; width: 100px; height: 100px; top: 200px; left: 200px; background-color: orange;"></div>
</body>

サンプルをみてみる。

これらのdiv要素はbody要素の直下に配置されています。『z-index』の値に数値が指定されている親要素が存在していませんので全ての要素は同じ『ルートスタックコンテキスト』に属しています。『z-index』は同じ『スタックコンテキスト』の『スタックレベル』を操作するプロパティなので上記のサンプルの場合は『z-index』に指定した数値の順番通りに表示されてたというわけです。

しかし以下の先ほどのサンプルをみてみましょう。

<div style="z-index: 2; position: absolute; width: 100px; height: 100px; top: 10px; left: 10px; background-color: red;"></div>
<div style="z-index: 3; position: absolute; width: 100px; height: 100px; top: 20px; left: 20px; background-color: blue;"></div>

<div style="position: relative; z-index: 1;">
    <div style="z-index: 100; position: absolute; width: 100px; height: 100px; top: 30px; left: 30px; background-color: purple;"></div>
    <div style="z-index: 150; position: absolute; width: 100px; height: 100px; top: 40px; left: 40px; background-color: orange;"></div>
</div>

この場合は『z-index』の値が『100』、『150』となっているdiv要素の親要素に『z-index: 1』と指定されていますね。ということは『z-index』の値に『100』と記述されていても『z-index: 1』と指定されている親要素が生成した『スタックコンテキスト』の中の『100』となります。なのでその手前にいる『z-index: 2』、『z-index: 3』と設定されているdiv要素の手前に来ることはできなかったのです。

『z-index: 1』となっている世界の中の『z-index: 100』と『z-index :150』なのでどんなに大きな数値を指定しても外の世界の『z-index: 2』の手前に来ることはできない、といったイメージでしょうか。そして違う世界(違うスタックコンテキスト)の奥行きの指定は『z-index』ではできません。あくまでも同じスタックコンテキストの中での奥行きの設定となります。

ではちょっと修正してみましょう。以下のサンプルは『z-index』の値が『100』、『150』となっているdiv要素の親要素の『z-index』の指定をやめてみました。つまり『auto』になっています。

<div style="z-index: 2; position: absolute; width: 100px; height: 100px; top: 10px; left: 10px; background-color: red;"></div>
<div style="z-index: 3; position: absolute; width: 100px; height: 100px; top: 20px; left: 20px; background-color: blue;"></div>

<div style="position: relative;">
    <div style="z-index: 100; position: absolute; width: 100px; height: 100px; top: 30px; left: 30px; background-color: purple;"></div>
    <div style="z-index: 150; position: absolute; width: 100px; height: 100px; top: 40px; left: 40px; background-color: orange;"></div>
</div>

サンプルをみてみる。

いかがでしょうか。単純に『z-index』の数値が大きい要素が手前に表示されていますね。この状態での全ての要素は『ルートスタックコンテキスト』に属しています。ということは同一の『スタックコンテキスト』に属していることになるので単純に『z-index』の数値の大きいほうが手前に表示されているという挙動になっています。

そしてもう一点ですが、『z-index』はマイナスの値を取ることができます。この値がマイナスだった場合も要注意です。

以下にサンプルを用意してみました。2つのdiv要素の『z-index』の値に『-1』、『-2』と設定し、その親要素のdiv要素には灰色の背景色と適当な大きさを指定し、そして『position: relative』と指定しています。『z-index』の値を設定していないので『z-index』の値は『auto』ですね。

<div style="position: relative; width: 1000px; height: 200px; background-color: silver;">
    <div style="z-index: -1; position: absolute; width: 100px; height: 100px; top: 10px; left: 10px; background-color: red;"></div>
    <div style="z-index: -2; position: absolute; width: 100px; height: 100px; top: 20px; left: 20px; background-color: blue;"></div>
</div>

サンプルをみてみる。

いかがでしょうか。子要素のdiv要素が灰色の親要素の奥に配置されているのが確認できたと思います。ここが注意なのですが、『z-index: auto』となっている要素の『スタックレベル』は『0』となります。ということは親要素であるdiv要素の『スタックレベル』は『0』なのでマイナスの値をとったdiv要素は全て奥へと配置されてしまいます。

では親要素であるdiv要素に『z-index: 0』と指定してみましょう。するとこのようなレンダリングになります。

<div style="z-index: 0; position: relative; width: 1000px; height: 200px; background-color: silver;">
    <div style="z-index: -1; position: absolute; width: 100px; height: 100px; top: 10px; left: 10px; background-color: red;"></div>
    <div style="z-index: -2; position: absolute; width: 100px; height: 100px; top: 20px; left: 20px; background-color: blue;"></div>
</div>

サンプルをみてみる。

灰色の親要素より子要素が手前に表示されているのが確認できたと思います。今は親要素に『z-index: 0』と指定しているので新しい『スタックコンテキスト』が生成されています。ここが間違いやすいところなのですが、上記のサンプルのように『z-index』の値をマイナスに設定しようとも属している『スタックコンテキスト』より奥へと配置されることはありません。『z-index』というプロパティは、あくまでも『同じスタックコンテキストの中で値が大きいほうを手前に表示することができる』というだけだったりしますので要注意です。

少し見比べてみましょう。前のサンプルの時の親要素の『z-index』は『auto』なので新しい『スタックコンテキスト』は生成されておらず、全ての要素は同じ『ルートスタックコンテキスト』に属していたことから親要素の『スタックレベル』は『0』、子要素のスタックレベルはマイナス、といった感じで親要素の奥へと配置されました。しかし、今回のサンプルでは親要素が『スタックコンテキスト』を生成しているので子要素の『z-index』にマイナスの値を設定しようとも親要素より奥に配置することはできなかった、という感じです。ややこしいですね。

あと昨今のブラウザではバグは大分減っていきましたが、一部のブラウザ(IE8とか)で『z-index』にマイナスの値を設定するとリンクが踏めなくなったりするバグもあります。なので『z-index』にマイナスの値を設定するのはなるべく避けるようにしたほうが無難かもしれません。

昨今のブラウザでの『z-index』の値に設定できる数値は符号付き32bit整数の最小値と最大値、つまり『-2147483647』から『2147483647』までの数値が取れたりします。

実際はこんな大きな数値を使うことはありませんが、意外と大きな数値も取り扱えるということだけ覚えておくとよいかもしれません。

そして『z-index』は『1』から順番に指定しなくてはいけない、といったルールは存在しませんので最初の要素にいきなり『10000』とかの大きい数値を設定しても問題ありません。

こちらも覚えておきましょう。

というわけで長々と難しい解説を入れてしまいましたがいかがでしょうか。先程も書きましたが『z-index』はそこまで頻繁に利用するプロパティではないので以下の項目を守れば大体何とかなります。

  • むやみに『z-index』を設定しないこと。
  • 思い通りの重なり具合にならないときは祖先要素の『z-index』の値に注目。
  • 『z-index』に設定する値はなるべく正の値で。

『z-index』を使用するとたまに思い通りできなくてハマってしまうことがあります。そんな時は『スタックコンテキスト』とか『スタックレベル』とかを思い出してみると良いかと思います。google先生に聞いてみましょう。

というわけで以上となります。

みなさまこれまでどうもありがとうございました。このような駄文をここまでお読み頂き大変光栄でございます。次の総まとめで忘れてしまったところとか再チェックしちゃってください。

ではまたお会いしましょう。

この記事は桜舞が執筆致しました。

著者が愛する小型哺乳類

桜舞 春人 Sakurama Haruto

ISDN時代から様々なコンテンツを制作しているちょっと髪の毛が心配な東京在住のプログラマー。生粋のロングスリーパーで、10時間以上睡眠を取らないと基本的に体調が悪い。好きなだけ寝れる生活を送るのが夢。ゲームとスポーツと音楽が大好き。誰か髪の毛を分けて下さい。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。