スクロールに応じてページ要素を固定表示できるposition: sticky
が便利で面白い使い方ができそうなので実験してみました。仕様がまだ草案(Working Draft)の段階 で、将来、細かい部分に変更がないとは言い切れませんが、Edgeを含めた最新のブラウザで、ほぼサポート されています。
フィーチャー・クエリ(@supports) と一緒に使えば、position: sticky
に対応していないブラウザにも考慮した実装が可能なので、注意は必要ですがちょっとしたエンハンスメントとして使うのに良さそうです。
まずは「こんなのが簡単にできちゃいますよ」というデモからご紹介します。
面白い使い方
基本的な使い方だけでも便利なスティッキーですが、応用するとスクロール効果のような面白い使い方ができます。以下、最新版のFirefox、Chrome、Safariあたりで見ていただけると確実に動いていると思います。
デモ1
デモ2
デモ3
デモ4
これらをJavaScriptなしで、すべてCSSだけで実装できるってすごくないですか?
テーブルとスペーサーGIFでページをレイアウトする時代にHTMLコーディングをはじめたので(いつ?昭和?笑)、現代の制作者がうらやましい限りですw
余談はさておき、上のデモの説明の前に、スティッキーの基本的な使い方を簡単にご紹介します。
position: stickyとは
数行のCSSでスクロールに応じて要素を固定表示することができます。たとえば、ページの途中にある要素がスクロールして最上部に来た際に固定できます。
こちらもデモを作ってみたので最新版のChrome、Safari、Firefoxあたりで見てみてください。
ベーシックな実装方法
上のデモのようにベーシックな実装をする場合、CSSとHTMLはシンプルです。
HTML
<h2>サブタイトル1</h2>
<p>
...
...
...
</p>
<h2>サブタイトル2</h2>
<p>
...
...
...
</p>
<h2>サブタイトル3</h2>
<p>
...
...
...
</p>
CSS
h2 {
position: -webkit-sticky;
position: sticky;
top: 0;
}
たった3行のCSSで、先ほどのデモのようにh2
をスクロールに合わせてページトップに固定することができます。ステッキーですよねw
要素の位置関係による挙動の違い
そんな素敵なスティッキーですが、スティック(固定)させる要素のDOM上の位置関係によって挙動にちょっとした差が生じます。
同じブロック内にある兄弟要素の場合
下のGIF動画のように、1つ目のスティッキー要素に2つ目のスティッキー要素が覆いかぶさるように表示されます。
たとえばh2
要素を固定するとして、以下のように兄弟要素の場合にこのような挙動になります。
<h2>サブタイトル1</h2>
<p>
...
...
...
</p>
<h2>サブタイトル2</h2>
<p>
...
...
...
</p>
異なるブロックにある要素の場合
下のGIF動画のように、1つ目のスティッキー要素を2つ目のスティッキー要素が押しのけるように表示されます。
以下のように固定する要素が異なるブロック内にある場合はこのような挙動になります。
<div>
<h2>サブタイトル1</h2>
<p>
...
...
...
</p>
</div>
<div>
<h2>サブタイトル1</h2>
<p>
...
...
...
</p>
</div>
この辺の挙動の違いとz-index
を上手く利用すると、先ほどのデモのような、ちょっと気の利いたスクロール効果を簡単に実装できます。
ということで、ここからは最初に紹介したデモのHTMLとCSSがどのように組まれているのかご説明します。
デモ1の説明
HTMLはいたってシンプルで、div
で分けられた5つのブロックがあって、その中に段落が入っています。基本的には、デモ1〜4までほぼ同じHTMLです。
<body>
<div class="block block-one">
<p>One</p>
</div>
<div class="block block-two">
<p>Two</p>
</div>
<div class="block block-three">
<p>Three</p>
</div>
<div class="block block-four">
<p>Four</p>
</div>
<div class="block block-five">
<p>Five</p>
</div>
</body>
CSSは、まず各ブロックがウィンドウの全てを覆うようにwidth: 100%
、height: 100vh
を指定しています。そして、Flexboxでalign-items
とjustify-content
を使って中のp
要素を中央に表示させています。さらに、position: sticky
、top: 0
を指定して、各ブロックがスクロールに応じてページ上部に固定されるようにしています。
.block {
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
position: -webkit-sticky;
position: sticky;
top: 0;
}
p {
display: inline-block;
font-size: 60px;
font-family: 'Great Vibes', cursive;
padding: 0;
margin: 0;
}
以下のCSSでそれぞれのブロックにz-index
を付与して後のブロックが前のブロックの上に重なるようにしています。
.block-one {
background: #212E32;
color: #fff;
z-index: 100;
}
.block-two {
background: #85937A;
z-index: 200;
}
...
デモ2の説明
デモ2では兄弟要素と異なるブロックにあるスティッキーの挙動の差を利用して表示に変化を与えています。CSSはブロックの高さをheight: 50vh
に変えただけで残りは同じです。HTMLはdiv
でセクションを2つに分けています。
<body>
<div>
<div class="block block-one">
<p>One</p>
</div>
<div class="block block-two">
<p>Two</p>
</div>
<div class="block block-three">
<p>Three</p>
</div>
</div>
<div>
<div class="block block-four">
<p>Four</p>
</div>
<div class="block block-five">
<p>Five</p>
</div>
</div>
<div class="block">
<p>Some more content</p>
</div>
</body>
デモ3の説明
デモ3では、3つ目のブロックに以下のCSSを追加して変化を加えています。HTMLはデモ2と同じです。
フィーチャー・クエリ(@supports
)を使ってposition: sticky
がサポートされる場合に背景色をnone
で上書きするように指定しています。フィーチャー・クエリを使わずに.block-three
にbackground: none
を指定してしまうと、sticky
がサポートされない場合に意図しない表示になってしまいます。
あと、@supports
でposition: -webkit-sticky
を入れないと、フィーチャー・クエリがSafariで思ったように動いてくれないので要注意です。
.block-three {
background: #586C5D;
color: #212E32;
z-index: 300;
}
@supports (position: sticky) or (position: -webkit-sticky) {
.block-three {
background: none;
}
}
また、.block-three
だけ、p
要素のスタイルを変えて違った効果を与えています。
.block-three p {
display: flex;
justify-content: center;
align-items: center;
width: 50%;
height: 50%;
background: #fff;
color: #212E32;
box-shadow: 0 1px 10px rgba(0,0,0,0.2);
}
デモ4の説明
デモ4では、ブロックに階層を設けて、各ブロックを上部に固定させるだけでなく、各セクションのタイトルも固定するようにしています。HTMLは、以下のようにdiv
でセクションを作って、それぞれにh1
を追加しただけです。
<h1>Section One</h1>
<div>
<div class="block block-one">
<p>One</p>
</div>
<div class="block block-two">
<p>Two</p>
</div>
...
</div>
<h1>Section Two</h1>
<div>
...
</div>
あとはh1
要素にスタイルを追加して上部にスティックさせるだけです。
h1 {
background: #FF6015;
color: #fff;
z-index: 1000;
margin: 6px;
padding: 10px;
position: -webkit-sticky;
position: sticky;
top: 6px;
left: 6px;
}
以上がデモの説明でした!
ブラウザ・サポート
ブラウザ・サポートを簡単にまとめると以下の通りです。詳しくはCan I use… を見てください。
- 最新のFirefox、Chrome(注1)、Safari(注2)、Edgeでサポートされています
- 注1: Chromeでは
thead
とtr
要素でsticky
が使えないそうです - 注2: Safariではプレフィックスが必要です(
-webkit-sticky
) - IEはサポートされてません
position: stickyを使う時の注意点
position: sticky
を使ってみて、いくつかハマったところや注意点をメモっておきます。
先祖要素にoverflowが指定されていると動かない
親要素にoverflow: hidden
を指定してfloat
を解除している場合、position: sticky
が使えません。これは、直近の親要素だけじゃなくて、先祖要素のいずれかにoverflow
が指定されているとダメみたいです。
float
を使ったグリッドシステムではposition: sticky
を使えない可能性が高いので注意が必要です。
overflow: hidden
、overflow: auto
だとsticky
が効かないoverflow: scroll
で高さの指定がないとsticky
が効かないoverflow: scroll
で高さの指定があると、そのブロック内でsticky
が効く。この場合、先祖要素にoverflow: hidden
が指定されていても関係ありませんoverflow: visible
だとsticky
が効く
inline-block要素がSafariでスティックしない
スティックさせたい要素にdisplay: inline-block
を指定するとSafariでスティッキーが効かなくなります。Firefox、Chrome、Edgeでは問題なくスティックするんですが、Safari(iOS Safariも)だけスティックしなくなります。
下のデモではオレンジに表示されているh1
要素にスティッキーが指定されてます。
サポートのないブラウザへの対応
position: sticky
がサポートされていないブラウザでは、プロパティが無視されるだけなので大きな問題はないと思うんですが、調整が必要な場合は@supports
とかModernizr を使って調整すると良さそうです。
ちなみに、@supports
を使う場合は以下のようにプレフィックスが入った方(position: -webkit-sticky
)も条件に入れないとSafariで認識されないのでご注意ください。
.block-three {
background: #586C5D;
color: #212E32;
z-index: 300;
}
@supports (position: sticky) or (position: -webkit-sticky) {
.block-three {
background: none;
}
}
ちなみに、上のCSSでは、まずposition: sticky
をサポートしないブラウザ向けのスタイルを記述して、@supports
を利用して対応ブラウザ向けのスタイルで上書きしています。
さいごに
ユーザが縦スクロールに飽きてるなんていう考察もある ようですし、こういった効果を簡単に実装できるのはありがたいですね。
Have fun sticking things to the edge!
2018年3月27日に公開され、2020年2月17日に更新された記事です。
About the author
「明日のウェブ制作に役立つアイディア」をテーマにこのブログを書いています。アメリカの大学を卒業後、ボストン近郊のウェブ制作会社に勤務。帰国後、東京のウェブ制作会社に勤務した後、ウェブ担当者として日英バイリンガルのサイト運営に携わる。詳しくはこちら。
ウェブ制作・ディレクション、ビデオを含むコンテンツ制作のお手伝い、執筆・翻訳のご依頼など、お気軽にご相談ください。いずれも日本語と英語で対応可能です。まずは、Mastodon @rriver@vivaldi.net 、Twitter @rriver 、またはFacebook までご連絡ください。
[…] 引用元:position: stickyの面白い使い方と使用時の注意点 […]