CSScss { position: sticky; } の基本的な考え方と設定方法
css
layout
position
sticky
以前はスクロール量を計測してヘッダーを上に固定とか、
スクロール量に合わせて要素を一旦固定・固定解放などの表現は、
Javascriptでしか表現できなかったのですが、
position: sticky;を使用することで、容易に実装することができるようになりました。
しかしながら実装するためには、position: sticky;の基本的な考え方を知らなければ設定できないので、
その辺りの知識・ノウハウを解説したいと思います。
スクロール方向が縦方向ということを前提に進めていきます。
基本中の基本
スクロール量によって要素を固定したいので、
位置を固定したい要素が入っている親要素が、ブラウザの縦幅よりも大きいものである。
要素を固定できる状態
※ 固定したい要素の親要素(グレーの領域)がブラウザの高さより大きいので赤い要素は固定できる
要素を固定できない状態
※ 固定したい要素の親要素(グレーの領域)がブラウザの高さより小さい為固定しようと思ってもできない
リキッドレイアウトのサイトにおいては、
サイトの縦幅がブラウザの横幅によって可変するので、
親要素の高さがなくなり固定できなくなることが起こり得るのでその点だけ注意してください。
基本となる設定
基本中の基本で表示した画像(要素を固定できる状態)のレイアウトを元にしたソースを掲載します。
header(位置を固定したい要素)
main
.header {
position: sticky;
top: 0;
height: 50px;
background-color: red;
}
.contents {
height: 2000px;
background-color: yellow;
}
.footer {
color:white;
height: 50px;
background-color: blue;
}
上記に記載したソースは.contentsの高さを 2000px に設定しています。
これは、要素内の "main" という文字列だけではブラウザの高さを超えることができない為です。
そして、PCでブラウザの高さを 2200px 以上にした際はブラウザ内をスクロールできなくなるので、
固定したい要素を固定できなくなります。
ここでなぜ 2200px なのかというと、
単純計算でdiv.wrapperの高さは header要素の高さ + main要素の高さ + footer要素の高さ = 2100px になります。
さらに、ブラウザのデフォルトで当たるスタイルがある(chromeの場合はbody要素に8pxのmarginがかかっている)為に、
若干ですが大きめに設定しています。
demoを用意しているので、確認はこちらから。
sticky による位置設定
縦方向でのスクロールを前提としている固定なので、
css としてはtop bottom を使うことになります。
top または bottom を設定した場合に基準点(0, 0)はどこになるかというと、
親要素(グレーの領域)の左上ではなく、
ブラウザの左上になります。
なので header要素に top: 0;を設定した場合は、
ブラウザの上部に張り付く形で固定されることになります。
left right を指定したときはどうなるのかというと、
横スクロールはできないので、
left: 0;やright: 0;を設定しても、
ブラウザの左右に張り付くことはなく、
親要素の枠内に収まったままになります。
このことから、
position: sticky;は、スクロール方向のみに効かせることが出来るcssプロパティだということがわかります。
position: sticky;は縦方向のスクロールに効かせた場合に下記の意味と同等となる。
position-x: relative;
position-y: sticky;
※ 実際にはないプロパティ名なのでニュアンスとして解釈していただければと思います。
サイドバーのあるレイアウトでサイドバーを固定する
こちらもデモを用意しました。確認はこちらから。
こちらもよくあるレイアウトで、aside要素であるサイドバーを固定する方法を考えてみます。
先に紹介した基本となる設定にaside要素を加え、
cssのdisplay: grid;で各要素を配置しています。
※ grid でのレイアウト方法については詳細を省かせていただきます。
ここで問題が発生しました。
aside要素の高さを出すためにmin-height: 400px;を設定しているのですが、
ブラウザの高さを 400px 近くにして最後までスクロールすると、
footer要素に被ってしまいます。
これはaside要素にposition: sticky;が効く事によって、
親要素であるdiv.wrapper内でfooter要素の下端の位置まで移動することが可能になったことから起こっている現象です。
この現象を解消するために下記のようにhtml構造を変更します。
合わせて、.wrapper で設定していたdisplay: grid;の使用をやめ、
.container でaside要素とmain要素を横並びにするのに、
display: flex;を使用して並ばせる事にします。
html構造の修正
header
main
header
main
cssの修正
.wrapper {
position: relative;
display: grid;
grid-template:
'header header' auto
'sidebar contents' auto
'footer footer' auto /
25% 75%;
padding: 50px;
}
.header {
grid-area: header;
height: 50px;
background-color: red;
}
.sidebar {
position: sticky;
top: 0;
grid-area: sidebar;
height: 50vh;
min-height: 400px;
color:white;
background-color: green;
}
.contents {
grid-area: contents;
height: 2000px;
background-color: yellow;
}
.footer {
grid-area: footer;
color:white;
height: 50px;
background-color: blue;
}
.wrapper {
position: relative;
padding: 50px;
}
.header {
height: 50px;
background-color: red;
}
.container {
display: flex;
}
.sidebar {
position: sticky;
top: 0;
width: 25%;
height: 50vh;
min-height: 400px;
color:white;
background-color: green;
}
.contents {
width: 75%;
height: 2000px;
background-color: yellow;
}
.footer {
color:white;
height: 50px;
background-color: blue;
}
html構造を修正したdemoはこちらになります。
これでfooter要素にかぶる事なく、要素の固定ができるようになりました。
sticky を使う上での注意点
position: sticky;が設定された要素の親要素・祖先要素のどれかに、
overflow: hidden;が設定されている場合、
スクロールによって固定したい要素は固定することができなくなり、
sticky を設定する前の状態で表示されます。
※ body要素にoverflow: hidden;が設定された場合はブラウザ自体がスクロールできなくなるので意味を成してくれません。
なので、
たまに見る慣性スクロールが実装されてヌルヌル動くようなページ・サイトでは、
body要素にoverflow: hidden;が使用されて、
ページをスクロールをさせないようにして実装されているためposition: sticky;は使うことができません。
自分でJavascriptの実装をする必要があります。
まとめ
スクロールで固定したい要素に対して、
position: sticky;を設定するだけで簡単にスクロール固定が実装できるようになっています。
しかしながら、
幾つかの注意点があり、下記に該当しないようにしないといけません。
1, 固定したい要素の親要素が、ブラウザよりも大きくページ自体がスクロールできること
2, 固定したい要素の親・祖先要素に、overflow: hidden;が設定されていない。
この情報が誰かのサイト制作の助けになれば幸いです。
そして、他のサイトにも設定方法が掲載されているので合わせて参考にしていただければと思います。