position: absolute を 1 つの例で
absolute で配置した要素は通常のフローから取り出され、top、right、bottom、left で配置されます。これらの位置は、position が static 以外の一番近い祖先から測られます。親に position: relative を付けるのはこのためです:
.card から position: relative を消すと、位置指定された祖先がなくなるので、バッジはページ全体の右上に飛びます。「position absolute が効かない」という疑問のほとんどは、この 1 行で説明できます。
absolute の要素について知っておきたいこと:
- 場所を取りません。 見出しと段落は、バッジがないかのように配置されます。
- 幅は内容に合わせて縮みます。
widthか、leftとrightの両方を指定した場合は別です。 - 位置は包含ブロックの padding の端、つまり border の内側から測られます。
position の 5 つの値
| 値 | フローに残るか | 位置の基準 | 主な使い道 |
|---|---|---|---|
static (初期値) | 残る | 位置の指定は無視される | 普通の要素 |
relative | 残る。元の場所も確保される | 本来の自分の位置 | absolute の子の基準、少しだけずらす |
absolute | 残らない | 一番近い位置指定された祖先 (なければページ) | バッジ、ツールチップ、オーバーレイ、閉じるボタン |
fixed | 残らない | ビューポート | ヘッダー、チャットボタン、Cookie バー |
sticky | 残る | 指定位置に達した後のスクロールコンテナ | テーブルの見出し、セクションのタイトル、サイドバー |
position: relative
relative の要素は、フローの中の元の場所にとどまります。位置を指定すると描かれる場所は動きますが、元の場所は確保されたままなので、周りは何も動きません:
ボックス 2 は 20px 下、20px 右に描かれてボックス 3 と重なりますが、ボックス 3 は動いていません。ボックス 2 の元の場所を空けたままです。relative だけで要素を動かすことはあまりありません。主な役割は、absolute の子の基準のボックスになることです。
位置の指定と inset
top、right、bottom、left には長さ、パーセント (包含ブロックが基準)、auto を指定できます。inset のショートハンドは、margin と同じ順番で 4 つをまとめて指定します:
.overlay {
position: absolute;
inset: 0; /* top: 0; right: 0; bottom: 0; left: 0; */
}
.corner {
position: absolute;
inset: auto 16px 16px auto; /* bottom right corner, 16px in */
}
向かい合う 2 辺を指定すると要素は伸びます。left: 0; right: 0 で包含ブロックと同じ幅になります。absolute の子に inset: 0 を指定するのが、カードをオーバーレイで覆う定番の方法です。
absolute と transform で中央に置く
top: 50%; left: 50% で、要素の左上の角が中央に来ます。続けて translate(-50%, -50%) で、要素自身のサイズの半分だけ戻します:
要素をフローに残せるなら、flexbox や grid のほうが簡単に中央に置けます。すべての方法の比較は div の中央寄せのページ にあります。
position: fixed
fixed の要素はビューポートを基準に配置され、ページをスクロールしてもその場にとどまります:
.chat-button {
position: fixed;
bottom: 16px;
right: 16px;
}
注意点が 2 つあります。fixed の要素は場所を取らないので、body に padding-top を付けないと、固定ヘッダーがページの上部を覆います。また、祖先に transform、filter、perspective があると、ビューポートではなくその祖先が基準になり、要素は祖先と一緒にスクロールします。
position: sticky
sticky の要素は、指定した位置に達するまでは普通にスクロールし、その後は親の終わりがスクロールで通り過ぎるまでそこに張り付きます。下のボックスをスクロールしてみてください:
各文字は、そのセクションが見えている間はスクロールボックスの上端に張り付き、次の文字に押し出されます。sticky の要素は親から出ることがないからです。
sticky が張り付かないときは、次を確認しましょう:
- 位置の指定がない。
top、bottom、left、rightのどれもなければ、position: stickyは何もしません。 - 祖先に
overflow: hidden、auto、scrollがある。 その祖先がスクロールコンテナになり、実際にスクロールしなければ何も張り付きません。はみ出しを隠すだけならoverflow: clipを使います。 - 親が sticky の要素と同じ高さしかない。 親の中に張り付く余地がありません。
- flex や grid の親が要素を引き伸ばしている。 flex の行の中なら、sticky のサイドバーに
align-self: flex-startを追加します。
よくある間違い
- absolute の要素の親に
position: relativeを付け忘れる。 - ページのレイアウトに absolute を使う。 absolute の要素はお互いも内容も無視するので、小さい画面で文字が重なります。レイアウトには flexbox か grid を使い、absolute は小さな装飾に使いましょう。
- static の要素に位置を指定する。
positionがなければtop: 10pxは何もしません。 - どの要素が上に来るかで悩む。 重なった位置指定された要素の順番は z-index で決まります。
- 固定ヘッダーが内容を隠す。 ページに padding を付けるか、
scroll-padding-topを指定して、アンカーリンクの移動先がヘッダーの下に来るようにします。
よくある質問
position: absolute は何をしますか?
要素を通常のフローから取り出し (ほかの要素はその要素がないかのように並びます)、top、right、bottom、left で配置します。基準は包含ブロック、つまり position が static ではない一番近い祖先です。
親要素を基準に absolute で配置するには?
親に position: relative;、子に position: absolute; と top: 0; right: 0; のような位置を指定します。位置指定された親がないと、子はページを基準に配置されます。
relative と absolute の違いは何ですか?
relative は要素をフローに残したまま描く位置だけをずらし、元の場所はそのまま残ります。absolute は要素をフローから取り出し、位置指定された祖先を基準に配置します。
position: sticky が効かないのはなぜですか?
たいてい次の 3 つのどれかです。top (などの位置) を指定していない、祖先に overflow: hidden や auto があってそれがスクロールコンテナになっている、sticky の要素の親がその要素と同じ高さしかなく、張り付く余地がない。
fixed と sticky の違いは何ですか?
fixed はフローから取り出され、ビューポートに固定されます (祖先に transform や filter がある場合を除く)。sticky はフローに残って普通にスクロールし、指定した位置に達すると、親が画面にある間だけ張り付きます。