今回は、CSSのpositionプロパティについて詳しく解説します。
positionはレイアウトに必須のプロパティなので、この記事を読んで必ず使えるようになりましょう。
目次
static
まずはposition: static;
についてです。
おそらくCSSを書いていてposition: staticを意識することはあまりありません。
positionの初期値はstatic
で、特に指定がなければstatic
になります。
leftやtopなどのプロパティで位置を変えることはできません。
.box {
position: static;
left: -1000000px; /* これは効かない */
}
デフォルトがstaticなので、特に記述する必要はありません。
また、重なり順を決めるz-index
も効きません。
relative
relativeは相対位置を指定する際に利用しますが、実際は以下のシチュエーションで使うのがほとんどです。
- absoluteを指定した要素の親要素として使う
- 要素の重なり順(z-index)を使う
absoluteについては後ほど出てきます。
まずは z-index で使う例です。
relativeはstaticを指定した場合の位置を基準に、topやleft、right、bottomで位置を動かすことができます。
以下はサンプルコードです。
<div class="relative-content">
<p>position: relative;</p>
</div>
<div class="relative-content relative-content-2">
<p>position: relative;</p>
</div>
.relative-content {
background-color: #eee;
position: relative;
padding: 20px;
margin-bottom: 20px;
z-index: 1;
box-shadow: 2px 2px 2px rgba(0,0,0,.2);
}
.relative-content-2 {
/* 指定なし */
}
このコードは以下の画像ようになります。

leftとtopを指定すると、
.relative-content {
background-color: #eee;
position: relative;
padding: 20px;
margin-bottom: 20px;
z-index: 1;
box-shadow: 2px 2px 2px rgba(0,0,0,.2);
}
.relative-content-2 {
left: 20px;
top: 60px;
}

こんな感じです。
次にtopを -60px 指定して、基準から60px上に移動してみます。
すると下にあったブロックが上に重なります。

position: relativeにすると、z-indexが使えるようになります。
この二つの要素に、z-indexを指定してみましょう。

重なり順が変わりました。このように、重なりが生じる時はz-indexを使って順番を決めるようにして下さい。
z-indexは数字の大きいほうが上に表示されるようになります。マイナスの指定も可能です。
absolute
次に absolute で使う場合です。
absolute は、基準からの絶対位置に配置するために使用します。基準となるのは、static以外が指定されている親要素です。
親要素にpositionを指定して、親要素の位置を基準にして配置します。
<style>
.relative-content {
width: 300px; height: 200px;
position: relative;
z-index: 1;
background-color: #eee;
}
.absolute-content {
position: absolute;
left: 30px;
top: 50px;
z-index: 1;
background-color: #ccc;
}
</style>
<body>
<!-- relativeが親要素、absoluteが子要素 -->
<div class="relative-content">
<div class="absolute-content">
<p>position: absolute;</p>
</div>
</div>
</body>
表示の例は下記の画像のようなイメージです。

position: absoluteは、絶対位置のため他の要素は関係なくその位置に来ます。そのため、下(z軸)にある要素の上に覆いかぶさります。
どの親要素にもstatic以外が指定されていない場合、ルート要素(html)が基準の位置となります。
仮に上記のコードで親要素のpostionをrelativeからstaticを指定して「どの親要素にもstatic以外が指定されていない」状態にします。そして上から120pxの余白を入れてみます。
<style>
.relative-content {
position: static;
margin-top: 120px;
/* 以下省略 */
下記の画像のようにルート要素(html)が基準の位置になります。

そしてこの状態で position: relative に戻してみます。
<style>
.relative-content {
position: relative;
margin-top: 120px;
/* 以下省略 */
すると absoluteは relative要素からの基準の位置になることが確認できます。

static以外を指定している兄弟要素(同じ親要素を持つ要素)が重なる時、z-indexの数字が大きい要素が上になります。
position: absoluteは多用しない
position: absoluteは一見簡単に配置ができますが、レスポンシブデザインとの相性はあまり良くありません。
基本的にはflexboxなどを使ってstaticのままレイアウトするのがベストで、position: absoluteの使用は最小限にしましょう。
fixed
まずはfixedを使ったDEMOを作りましたのでご確認ください。
スクロールしてもウィンドウの定位置に固定されているのが分かります。
top: 0 の位置に固定されています。
DEMOでは、下の container の要素でmargin-top: 50px; を指定して上の余白を設定しています。
fixedはウィンドウの左上を基準とした絶対位置になりますので、下の要素の上にかぶさってしまいます。
そのため、fixed領域のheight:20px と padding:15px(上下30px)分の50pxを余白としています。
<div class="header"> fixed ヘッダー - スクロールしても上に固定</div>
<div class="container">
1<br>2<br> <!-- 省略 --> <br>100
</div>
<style>
.header {
position: fixed;
top: 0;
height: 20px;
padding: 15px;
background: orange;
color: white;
z-index: 1000;
}
.container {
margin-top: 50px;
height: 200vh;
}
</style>
fixedのバグ
実は、position:fixedには「親要素にtransformが使われていると、相対位置になってしまうバグ」があります。
iOSのSafariのfixed注意点
もう一つ、iOSのSafariでも注意点があります。
JavaScriptでクラスを操作して、動的にposition:fixedが付与されるようにしてもうまく動きません。
CSS初心者にとっては「??」かもしれませんが、iOS SafariでJavaScriptを使って固定させる際、うまく固定できないことがあるのは頭に入れておきましょう。
position:fixedが使われているクラスに、transform: translate3d(0, 0, 0);を指定すると解決します。
sticky
意外と知られていないのがstickyです。以前はJavaScriptで行なっていた配置を、stickyだけで実装できるようになりました。
position: sticky;
は、「スクロールするまでは普通の位置にあるけど、特定の場所までスクロールすると固定される。」 という動作をする position
です。
良く使われるのは、ユーザーに見てもらいたいコンテンツをサイドバーに固定させたるパターンです。
topとbottomは縦スクロールされた時に固定される位置、leftとrightは横スクロールされた時に固定される位置です。
position: sticky
の特徴
・スクロールするまでは通常の relative
位置にある
・特定の位置に達すると fixed
のように画面上で固定される
・親要素の範囲内でしか固定されない、親要素が範囲外になると解除される(fixed
とは異なる)
この特徴について、先ほどの fixed のコードを fixed から sticky に変更して、margin-top: 50px を削除してみます。
DEMOを御覧ください。
<div class="header"> sticky ヘッダー - スクロールしても上に固定</div>
<div class="container">
1<br>2<br> <!-- 省略 --> <br>100
</div>
<style>
.header {
position: sticky; /* fixedからstickyに変更 */
top: 0;
height: 20px;
padding: 15px;
background: orange;
color: white;
z-index: 1000;
}
.container {
/* 削除 margin-top: 50px; */
height: 200vh;
}
</style>
次の要素に margin-top: 50px がなくても次の要素は被りませんでした。
これは、stickyの特徴、「スクロールするまでは通常の relative
位置にある」ためです。
スクロール前まではrelativeと同じように振る舞うため、その分、次の要素が自動で .headerの下から開始されます。
スクロールが開始(top: 0)されると.headerは固定になります。
また、headerの横幅(width)ですが、fixedの場合は文字数に応じた長さになりましたが、stickyの場合は横幅が最大の長さになっていることがわかります。
これは、fixedは(親要素)から完全に独立して配置されるため(絶対要素)、親要素の影響を受けないためです。widthを指定しない場合は、width: auto; となり、要素の中身で幅が決まります。
stickyの場合は親要素(ここではルート要素(html))の影響を受けるため、widthを指定しない場合はwidth: 100% となります。
最後に、親要素の範囲内でサイドバーに固定させ、親要素が範囲外になると解除させるパターン のstickyを使ったDEMOを作りましたのでご確認ください。
サイドバーは、スクロールすると top: 20px; の位置で固定 されます。
.sidebar {
position: sticky;
top: 20px; /* スクロールすると top: 20px; で固定 される */
.sidebar-container サイドバーの親要素 の高さ height: 800px で画面をこの親要素を超えると固定が解除されます。
.sidebar-container {
height: 800px; /* これを超えると sticky が解除される */
全体のコードです。
<div class="container">
<!-- サイドバーの親要素 -->
<div class="sidebar-container">
<!-- サイドバー -->
<div class="sidebar">サイドバー - スクロールすると固定され、親要素を超えると解除</div>
</div>
<!-- メインコンテンツ -->
<div class="content">
<h2>position: sticky の DEMO</h2>
<p>スクロールして動作を確認してください!</p>
</div>
</div>
.container {
display: flex; /* コンテンツとサイドバーを横並びに配置 */
max-width: 1000px;
margin: auto;
padding: 20px;
}
/* サイドバーの親要素(これを超えると固定解除) */
.sidebar-container {
width: 300px;
height: 800px; /* これを超えると sticky が解除される */
background: #ddd;
padding: 10px;
}
/* サイドバー - スクロールで固定、親の高さを超えると解除 */
.sidebar {
position: sticky;
top: 20px; /* スクロールすると top: 20px; で固定 される */
background: lightblue;
padding: 20px 15px;
height: 200px;
}
/* メインのコンテンツエリア */
.content {
flex: 1;
padding: 20px;
background: #f4f4f4;
min-height: 2000px; /* スクロールテストのため */
}
can I useを見てみると、主要ブラウザの全てでサポートされるようになりました。
IEが使われていた時代では同じレイアウトをJavaScriptを使って実現していましたが、IEのサポートが終了した今、sticky
を使わない理由はありません。
position: stickyの注意点
親要素にoverflow: hidden か overflow: auto があると、position: stickyが使えなくなります。
overflowに関連する注意点はいくつかあり、一部を紹介すると以下の内容です。
- overflow: hidden、overflow: autoだとstickyが効かない
- overflow: scrollで高さの指定がないとstickyが効かない
- overflow: scrollで高さの指定があると、そのブロック内でstickyが効く。この場合、先祖要素にoverflow: hiddenが指定されていても関係ありません
- overflow: visibleだとstickyが効く
position: stickyの注意点については、上記引用元の記事に詳しく書かれています。
z-indexのつけ忘れに注意
positionを使ってレイアウトをしていると、要素が突然消えてしまうことがあります。初心者の頃はこれで焦りました。
多くの場合z-indexを指定していないために、他の要素の下に隠れてしまっているのが原因です。
absoluteやfixed、stickyを使う時はz-indexが指定するようにしましょう。
まとめ
Webサイトをレイアウトするには、positionプロパティは必ず覚えておく必要があります。
要素をスクロール追従・固定配置したり、要素内の中央に配置したりと、様々な場面で活躍します。
使い方がよく分かっていないという人は、しっかり学習して使えるようになりましょう。
他にもこんな記事があります。

【CSS】中央寄せ「margin: 0 auto」が効かない!?その理由と…
今回は、CSSで中央寄せをする際に使用する「margin: 0 auto」が効かない時の理由を解説し…

【CSS】clip-pathで背景を斜めに切り抜く方法
今回は、背景を斜めに切り抜く方法を紹介します。Webデザインでよくある表現として、背景を斜めにするデ…

【CSS】display: contents の使用方法!便利な使い方を例を交…
今回は「display: contents」について解説します。displayプロパティはよく使用す…