本ブログではCSSのpositionプロパティの値であるstatic, fixed, relative, absoluteの使い方について解説済みですが、その記事中で触れていなかったもう一つのpositionプロパティの値stickyについて本記事で解説したいと思います。特定の要素をある場所で固定して表示させたい時に利用されるプロパティなのでしっかり理解して利用できるようにしましょう。

CSSのpositionプロパティの値であるstatic, fixed, relative, absoluteの使い方については下記の文書を参考にしてください。

stickyとは

stickyは、日本語では”粘着する”という意味で訳される単語です。この名前の通り、positionプロパティでstickyを設定した要素は画面をスクロールしてその要素が画面上に現れ事前に指定した場所にスクロールが進むとその場所に固定することができます。1度固定したら終わりというわけではなく、今度はスクロールを元の位置に戻すと固定が解除され、本来あるべき場所に表示されます。

言葉では理解するのが難しいかもしれないので、実際にstickyが設定されているページで確認してみましょう。本ブログでは、サイドバーに配置した目次にstickyを使用しています。試しに本文書の下まで画面をスクロールしてください。右側に目次が現れてからさらにスクロールするとブラウザ上に固定される目次を確認することができるかと思います。下まで行ったら再度トップまで戻ってみてください。目次が最初に出た場所(本来あるべき場所)に戻ると固定は解除されます。

スマホで閲覧している人にはサイドバーが表示されないので動作確認を行うことはできません。また、IEなどの一部のブラウザやバージョンではstickyがサポートされていないため、上記で説明したような動作は確認できない場合があります。

stickyの設定方法

p要素にstickyを設定する場合は下記のようになります。

positionプロパティのsticky設定
positionプロパティのsticky設定
MACユーザでsafariを使用している人は、以前はpositionの設定に-webkit-stickyを設定しなければ動作しませんでしたが今はサポートしています。

topプロパティに10pxと設定した場合は上部から10pxの位置から固定が開始されます。要素の上部に空白を作りたい場合等に活用できるかと思います。

stickyを設定したが動作しなかった例

stickyを設定すればどんな要素でも簡単に固定ができると思うかもしれませんがstickyを設定するためには簡単なルールを守る必要があります。このルールを守らなければstickyが動作しないのでよく理解しておきましょう。

要素にstickyを設定したとしてもその親要素に高さがない場合は動作しません。下記のように2カラムのレイアウトで、カラム全体では十分な高さはありますが、stickyを設定した要素の親要素の高さが制限されている場合は、画面をスクロールしても固定されません。モニターの位置にスクロール(モニターに映っている部分)しても固定されていないためモニター上に要素は表示されません。

親要素に十分な高さがない場合
親要素に十分な高さがない場合

親要素の高さが十分にある場合は、モニターの位置までスクロールするとブラウザ上で要素を確認することができます。

親要素に十分な高さがある場合
親要素に十分な高さがある場合
stickyは親要素の範囲内でしか動くことができないため、親要素に高さがないと固定することができません。positionではstickyに限らず、親要素との関係が重要になります。

Flexboxの場合

Flexboxで作成したレイアウトでstickyを実践してみよう

実際にFlexboxで2コラムのレイアウトを作成してstickyの動作確認を行ってみましょう。

動作確認を行うために作成したレイアウトをブラウザで表示すると下記のようになります。

Flexboxを利用して2カラムレイアウト作成
Flexboxを利用して2カラムレイアウト作成

containerクラスを持つ親要素divの下にmainクラスとsidebarクラスを持つ子要素divで構成されたシンプルなものです。containerクラスにflexboxを設定します。


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>sticky</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body> 
<div class="container">
    <div class="main">
        <h1>メイン</h1>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem voluptate magni excepturi, sit earum nulla quia consequatur eaque reprehenderit, molestiae dolores. Eos natus, voluptatibus nisi optio! Repudiandae ratione, perspiciatis voluptate!</p>
//略
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem voluptate magni excepturi, sit earum nulla quia consequatur eaque reprehenderit, molestiae dolores. Eos natus, voluptatibus nisi optio! Repudiandae ratione, perspiciatis voluptate!</p>
    </div>
    <div class="sidebar">
      <div class="list">
       <p>サイドバー</p>
       <p class="sticky_part">固定したい要素</p>
      </div>
    </div>
</div>
</body>
</html>

下記のCSSを適用しています。containerのdisplayプロパティにflexを設定し、mainとsidebarを2:1の2カラムレイアウトにしています。各領域が区別しやすいように背景色を設定しています。stickyで固定したい要素には、sticky_partクラスを設定し、positionプロパティとtopプロパティの設定を行っています。


p{
    margin: 0;
    padding: 0;
}
/* Flexコンテナ― */
.container{
    display: flex;
}
/* Flexアイテム */
.main{
    flex:2;
    background-color: #51e3d4;
}
/* Flexアイテム */
.sidebar{
    flex:1;
}
/* 固定したい要素の親要素 */
.list{
    background-color: #f3ecd3;
}
/* 固定したい要素のCSS */
.sticky_part{
    top:30px;
    position:sticky;
    background-color: #474f85;
    color:#fff;
}

親の要素に高さがない場合の動作

sticky_partクラスを設定したp要素の親要素は、listクラスを持つdiv要素になります。背景色で確認できるように親要素には背景色をつけていますが、高さが十分にないことがわかると思います。

Flexboxを利用して2カラムレイアウト作成
Flexboxを利用して2カラムレイアウト作成

この場合、画面を下記にスクロールしても固定したい要素がブラウザ上に固定されることはありません。理由は親の要素に高さがないため、下に動く領域がないためです。

親要素に高さが十分にある場合の動作

親要素に高さを持たせるためにここではheightプロパティを100%に設定します。


.list{
    background-color: #f3ecd3;
    height:100%;
}

heightプロパティを100%に設定するとlistクラスを持つdivの領域が縦一杯に広がるのが、背景色で確認できます。縦一杯に広がらない場合には動作しません。height:100%で縦に広がらない場合はheightの値を100%ではなく値を設定してみてください(Safari)。

親要素の要素の高さが十分にある場合
親要素の要素の高さが十分にある場合

この設定で、下に向かってスクロールを行うとブラウザに固定したい要素が固定されるが確認できます。topプロパティを30pxに設定しているので、固定したい要素の上部には30px分の領域があります。

画面をスクロールすると固定される
画面をスクロールすると固定される

Gridの場合

レイアウトを作成する場合にFlexboxではなくGridを利用する場合もあります。FlexboxとGridでは違いがあるのかを確認します。

HTML分は先ほどと同じです。


<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>sticky on Grid</title>
    <link rel="stylesheet" href="css/style.css" />
  </head>
  <body>
    <div class="container">
      <div class="main">
        <h1>メイン</h1>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem
          voluptate magni excepturi, sit earum nulla quia consequatur eaque
          reprehenderit, molestiae dolores. Eos natus, voluptatibus nisi optio!
          Repudiandae ratione, perspiciatis voluptate!
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem
          voluptate magni excepturi, sit earum nulla quia consequatur eaque
          reprehenderit, molestiae dolores. Eos natus, voluptatibus nisi optio!
          Repudiandae ratione, perspiciatis voluptate!
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem
          voluptate magni excepturi, sit earum nulla quia consequatur eaque
          reprehenderit, molestiae dolores. Eos natus, voluptatibus nisi optio!
          Repudiandae ratione, perspiciatis voluptate!
        </p>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem
          voluptate magni excepturi, sit earum nulla quia consequatur eaque
          reprehenderit, molestiae dolores. Eos natus, voluptatibus nisi optio!
          Repudiandae ratione, perspiciatis voluptate!
        </p>
      </div>
      <div class="sidebar">
        <div class="list">
          <p>サイドバー</p>
          <p class="sticky_part">固定したい要素</p>
        </div>
      </div>
    </div>
  </body>
</html>

style.cssの中のスタイルをflexboxからgridに変更します。gridの列は2列に設定を行っています。


p {
  margin: 0;
  padding: 0;
}
/* Grid */
.container {
  display: grid;
  grid-template-columns: 2fr 1fr;
}

.main {
  background-color: #51e3d4;
}

.list {
  background-color: #f3ecd3;
  height: 100%;
}

/* 固定したい要素のCSS */
.sticky_part {
  top: 30px;
  position: sticky;
  background-color: #474f85;
  color: #fff;
}

GridとFlexboxでは違いはなく、同様にStickyが行われることが確認できます。

画面をスクロールすると固定される
画面をスクロールすると固定される

まとめ

FlexboxとGridを使用した単純な2コラムレイアウトでstickyの動作確認を行いました。ルールを知っていればCSSを数行増やすだけでsticky機能を実践することができます。sticky機能を利用する場合は親要素の高さが十分なのかどうか確認を行ってください。