SVGコーディングブック
Apple Booksでみる
こんにちは、「ふ」です。
今回はCSSのposition:fixedとsticky、2つの値について深掘りしていきます。
「スクロールに関わらず、画面上に要素を固定する」方法を調べたとき。position:stickyを使う方法と、fixedを使う方法、いずれの情報も出てきます。
これら2つの値、どのように使い分ければいいのか。
双方の特徴を挙げてみると、
◾️ fixed
・viewPortに対してレイアウトされる。
・<body>内に表示領域は確保されない。
◾️ sticky
・親要素に対してレイアウトされる。
・親要素に表示領域が確保される。
・兄弟要素の前後関係は厳守される。
〜といったところです。
で。この違いが具体的にはどのような挙動を示すのか。
fixedとsticky、それぞれの特徴と使いどころについて紹介していきます。
◾️ fixed
・viewPortに対してレイアウトされる。
・<body>内に表示領域は確保されない。
position:fixedを指定された要素は、viewPort(画面)に対して別レイヤー(層)を設け、そこに要素を固定します。<body>のスクロールの影響を受けなくなるため、画面上に固定されるようになります。
「viewPort」という言葉が聞き慣れないかもしれません。viewPortは、「ブラウザを表示している部分」という意味です。PCならブラウザのウインドウ部分、スマホなら画面全体に相当するでしょう。
それではサンプルを元に、実際の挙動を観察してみましょう。
<body>
<p class = "fixed">
fixed
</p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
</body>
.fixed {
「「3/*単なる装飾です⬇︎*/」」
background-color:rgba(222,184,135,0.6);
height:15vh;
font-size:8vh;
font-weight:bold;
text-align:center;
color:#555;
padding-top:2vh;
}
.scroll_area {
height:60vh;
background-color:aliceblue;
border:solid 1px;
}
1ばん上に固定用の<p>要素をおき、その下に高さ60vhの<p>要素をいくつか配置しています。
⬆︎をスクロールさせてみてください。今のところは全ての要素がフツーにスクロールしています。
1ばん上の<p>要素に対してposition:fixedを指定してみましょう。
.fixed {
「「3 〜略〜 」」
position:「「1fixed」」;
top:0;
left:0;
}
position:fixedを指定するときは上下左右の位置指定を明示してやるようにしましょう。
position:fixedとした要素が、スクロールしても画面上に固定されたまま動かなくなりました。
また<p>要素はブロック要素のはずなので横幅はいっぱいに広がるはずなのですが、テキストの部分しか背景色がついていません。position:fixedにするとinline-block要素のような振る舞いをするみたいです。
.fixed {
「「3 〜略〜 」」
position:fixed;
top:0;
left:0;
width:「「1100%;」」
}
widthを「100%」と明示してやると、要素がviewPortいっぱいに広がりました。
position:fixedをレイアウトする際には、widthなどもあらためて明示してやる必要があります。
そしてここで、<body>全体の幅を狭くしてみます。
body {
width:60%;
margin:0 auto;
}
<body>の幅を60%とし、水平方向中央に寄せています。
fixedした要素は本来<body>の子要素なので、親要素とともに幅が縮まるはずなのですが、いまだ画面いっぱいに広がってしまっています。
position:fixedとした要素は親子構造に関わらず、強制的にviewPortに対してレイアウトされていることがわかります。
position:fixedを指定した要素はviewPortに用意された新たなレイヤーに貼り付けられるため、元の<body>内に確保されていた表示領域はキャンセルされてしまいます。
<body>
<p class = "fixed">
fixed
</p>
<p class = "scroll_area">
おはよう<br>
こんにちは<br>
こんばんは
</p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
</body>
fixed要素のすぐ下の「.scroll_area」にテキストを入れてみました。
結果⬆︎です。テキストがfixed要素の背面に回り込んでしまっています。
本来ブロック要素は上からその表示領域が確保されながら、順に並べられていくのですが、1ばん上の<p>要素にpositon:fixedが施されたため、そのぶんの表示領域がキャンセルされてしまったのです。
2ばん目の<p>のテキストをちゃんと表示させるには、キャンセルされた領域ぶんの余白を設けてやる必要があります。
position:fixedの「viewPortに絶対配置される」という特性は、レスポンシブを構成するときに便利です。
<body>
「「3<!--topに戻るボタン-->」」
<button class = "to_top">
top⬆︎
</button>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<body>
topに戻るボタンを作ってみました。
.to_top {
background-color:rgba(222,184,135,0.6);
height:15vh;
font-size:5vw;
font-weight:bold;
text-align:center;
color:#555;
width:20%;
「「3/*fixedでviewPort左下に配置*/」」
position:fixed;
bottom:10px;
left:10px;
}
ボタンをfixedとし、画面左下に配置します。
すると<body>や画面の幅にかかわらず、<button>は常にviewPort左下に配置されるようになります。PC/スマホ間でいちいちレイアウトを組み直す必要がなく、便利です。
本来の親要素である<body>ベースのレイアウトでこのような実装をするとしたら、画面幅を検出したりtransformを駆使したりと、かなり大変な作業となってしまいます。
viewPortベースのレイアウトができるposition:fixed。有効に活用してください。
◾️ sticky
・親要素に対してレイアウトされる。
・親要素に表示領域が確保される。
・兄弟要素の前後関係は厳守される。
つぎはposition:sticky。fixedとの大きな違いは、親要素に対してレイアウトされるという点です。
<body>
<p class = "sticky">
sticky
</p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
</body>
先ほどと同じようなHTMLを組み、
.sticky {
「「3/* 〜単なる装飾は略〜 */」」
position:「「1sticky」」;
top:0;
}
1ばん上の<p>要素にposition:stickyを指定します。このとき、top/bottomなどの位置指定を明示するようにしてください。でないとstickyが機能しません。
現在の状態⬆︎。スクロールに関わらずsticky要素が上部に固定されます。
stickyの場合は親要素に対してレイアウトされるため、<p>などのブロック要素はwidthを明示しなくても、デフォルトで親要素の100%となります。
ここで親である<body>要素の幅を変更してみましょう。
body {
width:60%;
margin:0 auto;
}
<body>の幅に合わせて、sticky要素も縮まりました。fixedとは違い、stickyは親要素のレイアウトを元に描画されるのです。
<body>要素のスタイルを生かしつつ要素を固定させてたいときは、position:stickyのほうが便利ですね。
stickyも一見、html全体に対して固定されているように思えるのですが、そうではありません。親要素のviewPortに入っている部分に対して固定されているのです。
通常<body>要素の一部は常にviewPortに入っています。今の例では<body>が直近の親要素であったため、fixedと同じようなふるまいに見えていたのです。
<body>
「「2<div>」」
<p class = "sticky">sticky</p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
「「2</div>」」
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
</body>
試しにsticky要素を<body>直下ではなく、<div>の入れ子にしてみました。
これでsticky要素の直属の親要素は<div>要素となります。この親要素にはstickyのほかに3つの<p>要素も配置しています。
sticky要素を<div>要素の入れ子にした結果です。
<div>要素がviewPortに入っている間はその上部に固定されていますが、<div>がviewPortから消えていくとき、sticky要素も一緒に外に消えていきます。
これがsticky要素が直属の親要素に対してのみ固定されている、という状態です。
この特性は、一定の範囲のみ画面上に要素を固定したいときに有効です。くわしい実装方法は⬇︎の記事で紹介しています。
〽️ position: stickyが便利すぎる。
position:stickyは親要素に対してレイアウトされるため、親要素の内部にその表示領域がちゃんと確保されます。
<body>
<p class = "sticky">
sticky
</p>
<p class = "scroll_area">
おはよう<br>
こんにちは<br>
こんばんは
</p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
</body>
fixedの例と同じ要領で、1つ下の「.scroll_area」にテキストを入れてみました。
結果⬆︎。fixedのときとは違い、隣接している<p>要素のテキストが隠れることなく表示されています。これは、親要素の中にsticky要素の領域が確保されているということです。
.sticky {
「「3/* 〜単なる装飾は略〜 */」」
position:sticky;
top:「「150%」」;
}
ここで、topの位置を「50%」にしてみました。
sticky要素は親要素のtopから50%の位置に固定されます。
ただし、1ばん上までスクロールしてみてください⬆︎。sticky要素の表示領域は確保されたままで、余白状態となってしまっています。
「要素の表示領域が(強制的に)確保される」という性質は、メリットもデメリットも持っていますね。topやbottomを0にするぶんには、何の問題もなく便利に扱うことができます。
いっぽう、中間位置などに固定させたい場合は不向きですね。
position:stickyのもう1つの性質として、位置指定方向の外側に対しての、要素の順序は厳守されるというものがあります。
上からsticky要素→隣接要素の順にて並んでいたとします。
sticky要素の位置指定を「top:0」としたとき。指定の基準は「上から」ということになります。
現在sticky要素は「上方向」に対して1ばん外側に配置されているので、これは問題なく親要素の上部に固定されます。
同じく「top:0」で、sticky要素が上から2ばん目にあるとき。
「上方向」ということで考えると、sticky要素の外側に別の要素が1つ存在することになります。
sticky要素は、この外側にある要素より上に固定させることができません。
これは「bottom:0」のときにも同じことが言えます。
bottom指定なので「下方向」で考えると、sticky要素の外側に別の要素があります。この要素より下にsticky要素を固定することはできません。
〜実際にコードを書いて、試してみましょう。
<body>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "sticky">
sticky
</p>
</body>
ずっと上部固定でやっていたので、今度は1ばん下にsticky要素を配置しました。
.sticky {
「「3/* 〜単なる装飾は略〜 */」」
position:sticky;
bottom:「「10」」;
}
bottomを「0」に指定します。
現在sticky要素は「下方向」の1ばん外側にあるので、常に親要素の下部に固定されます。
<body>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "scroll_area"></p>
<p class = "sticky">
sticky
</p>
<p class = "scroll_area"></p>
</body>
CSSの指定はそのままに、sticky要素を下から2ばん目にしてみます。
結果⬆︎。sticky要素は「下方向」において内側にある要素に対してはちゃんと下部固定されているのですが、「下方向」的に自身より外側の要素に対し、追い越して下部固定することはできなくなっています。
position:stickyを使用する際には、位置指定方向の1ばん外側に要素を配置するようにしてください。
ここまでposition:fixed/stickyの性質について深〜く見てきました。使い分けについてまとめてみます。
<body>などの親要素の影響を受けず、vierwPortに絶対配置させたいときはposition:fixedを使うべき。
・他要素の影響を受けないので、柔軟な配置に対応させることができます。
・要素の領域が確保されないので、背後に回るコンテンツとの重なりには配慮するようにしてください。
<body>などの親要素の幅でサクッと固定させたいときには、position:stickyが便利です。親要素のレイアウトが継承されるため、widthなどの調整が不要です。
・範囲を限定して固定させることが可能。
・要素の領域が親要素内に強制的に確保されるため「top:50%」など、スクロール方向の始点/終点以外の固定には不向き。
・兄弟要素との順番に注意すること。
〜以上の点をふまえて、状況に合ったほうを利用するようにしてくださいね。
最後までお読みくださり、ありがとうございました。
ではまた〜 🎵
ベクターグラフィック、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。