position:stickyが効かない原因

position:aticky

最初は通常のレイアウト配置(static)、
スクロールすると指定の絶対位置に固定され(fixed)、
次のsticky要素が来ると相対位置に固定(absolute)される 「position: sticky」。

とりあえずサンプルを作りました。divタグにsticky が指定されているので上から折り重なるような挙動になります。

See the Pen sticky sample by Takashi Abe (@TakeshiAbe) on CodePen.

見出しの固定やメニューバーの固定など使い途は多いのですが、仕様が分かっていないとエラーに見舞われがちです。
シンプルですので、ささっと理解しておきましょう。

Stickyの基本仕様とエラー

stickyを指定した要素は、スクロールにあわせて「stickyを指定した要素の親要素(以降、stickyコンテナ)」の中で絶対または相対的に自動で固定されます。

これを踏まえてエラーが起こる原因と解決法を書いていきます。ちなみにtop:0にstickする前提で書いていますが、横スクロール時やbottom指定する場合は例もあります。どちらも後述します。

position:sticky がエラーとなる3つの原因

親要素の高さを超えている

stickyアイテムはstickyコンテナのheightの中で自分の位置を計算しています。

stickyアイテムがstickコンテナの高さを超えている場合、位置を計算できなくなってしまいstickyは動作しなくなります。
コンテナのheightを指定しない、またはコンテナheight > stickyアイテムheight に変更することで解決します。

stickyコンテナの中に要素が1つしかない

stickyコンテナの中に要素が1つしかない場合、その要素にstickyを指定しても意味がありません。

stickyを指定している階層が異なっている

類似のエラーとして、stickyを指定している要素が兄弟関係でなく親子関係になっていたり全く別の階層にある場合も同様に予期しない動きやエラーとなります。

たとえば、次のコードではh2タグ全てをposition:stickyとしていますが、divタグの中にあるh2とそうでないものがあります。どうなるでしょうか?

<!-- h2タグそれぞれにstickyを指定 -->
<h2>Sticky-1</h2>

<div>
   <h2>Sticky-2</h2>
   <p>abcdefg</p>
</div>

<div>
   <h2>Sticky-3</h2>
   <p>hijklmn</p>
</div>

<h2>Sticky-4</h2>
<p>opqrstu</p>
<p style="margin-bottom:50vh">vwxyz</p>

実際の動きが次のサンプルです。

See the Pen sticky -sample by Takashi Abe (@TakeshiAbe) on CodePen.

sticky-2とsticky-3はそれぞれコンテナ(div)の中でのみ固定化され、他に影響することはありません。

一方で sticky-1と sticky-4は同じコンテナ内の兄弟要素となっている為、sticky-4が来るまでsticky-1はtop: 0;に固定されたままです。

親、先祖要素のoverflow

ある意味バグだと思いますが、親要素も含めた先祖要素の「overflow / overflow-y」プロパティに初期値(visible)以外が指定されている場合、stickyは無効化されます。

ただし、横方向へのsticky指定である場合は問題なく動作します。

次のサンプルでは親要素にoverflow-x:scroll 、thタグにposition: sticky ;を指定していますが、問題なく動作します。

See the Pen sticky sample2 by Takashi Abe (@TakeshiAbe) on CodePen.

bottom固定もできる

position: sticky は多くの場合 top: 0 ; で上部に固定されますが、逆にbottom: 0 ;を指定するとフッター固定することも可能です。bottom固定はstickyアイテムが1つでもエラーになりません。

特にモバイルでは操作性の面からフッターにメニューバーやSNSアイコンを固定することも多いので、stickyが役に立つと思います。

See the Pen sticky sample3 by Takashi Abe (@TakeshiAbe) on CodePen.

タイトルとURLをコピーしました