【CSS】positionのrelative、absolute、fixed、stickyの使い方を解説

今回は、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は数字の大きいほうが上に表示されるようになります。マイナスの指定も可能です。

豊富なオリジナルブロックでLPをかんたんに作成できるLP Creator

LPをかんたんに作成できるLP Creator

デザイン・機能・SEO・収益化にこだわったメディア運営者向け「STREETIST」

デザイン・機能・速度・SEO・収益化にこだわった、ブロガー・メディア運営者向けのデザインテーマ STREETIST

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の面白い使い方と使用時の注意点

position: stickyの注意点については、上記引用元の記事に詳しく書かれています。

z-indexのつけ忘れに注意

positionを使ってレイアウトをしていると、要素が突然消えてしまうことがあります。初心者の頃はこれで焦りました。

多くの場合z-indexを指定していないために、他の要素の下に隠れてしまっているのが原因です。

absoluteやfixed、stickyを使う時はz-indexが指定するようにしましょう。

まとめ

Webサイトをレイアウトするには、positionプロパティは必ず覚えておく必要があります。

要素をスクロール追従・固定配置したり、要素内の中央に配置したりと、様々な場面で活躍します。

使い方がよく分かっていないという人は、しっかり学習して使えるようになりましょう。


他にもこんな記事があります。

(PR)LPをかんたんに作成できるLP Creator