position: stickyが効かない場合の解決方法【CSS】

position-sticky-and-overflow-hidden

CSSで要素をページ上の指定位置に固定する方法のひとつとして、position: stickyを利用する方法があります。よく使われる用途としてはサイドバーの固定とかでしょうか。非常に簡単に利用できるため、使用を検討している方も多いかと思います。しかし、position: stickyは祖先要素にvisible以外のoverflow属性が指定してあると期待通りに動作しない場合があります。この記事では、この症状の詳細と解決方法を紹介します。

  • 「サンプルコード通りにstickyを指定したんだけれど、全くスクロールに追従してくれない。」
  • 「コンテナの高さや幅は正しいはず...。うまくいかない原因がわからない。」

という方はこの記事を読むと解決できるかもしれません。

position: stickyが効かない理由

要素をスクロールに追従させる場合などによくやるstickyを使った記述方法は以下のようなものです。

.sticky-content {
  position: sticky;
  top: 0;
}

本来であれば、sticky-contentを与えた要素がスクロールに追従することが期待されます。fixedと違って、親要素の領域内でのみ動くことができるのが特徴です。しかし、上記のように記述をしてもうまく固定されてくれない場合があります。

この症状の原因として、position: stickyの祖先に、visible以外のoverflow属性値が指定されていることが考えられます。ここで言う祖先とは、「対象要素の親、そのまた親、…」といった風に親要素を辿ることで訪れることができる全ての要素を指しています。

チェック方法

自分の環境で、position: stickyが効かない理由がoverflow属性であるかどうかは以下のようなJavaScriptコードを実行することで確認できます(JQueryを使用しています)。このコードでは、.sticky-contentの祖先全てのoverflow属性値をvisibleに変更しています。実行後にstickyが正しい挙動になる場合、overflow属性が原因であると言えます。

$(".sticky-content").parents().css("overflow", "visible")

簡単に使用するには、Webブラウザのコンソール画面にこのコードを貼り付けて実行すると良いです。.sticky-contentの部分は、ご自身の環境でpositionを指定している要素を返すように書き換えてください。

解決方法

上記の方法で原因の調査をした結果、overflow属性値が原因であった場合の解決方法は何があるのか紹介します。「うまくやることで祖先要素のoverflow: hidden等とpositon: stickyを両立する」といったことはできないので注意してください。

親要素全てのoverflow属性値をvisibleに変更する

まずはじめに思い浮かぶ解決方法は、stickyにしたい要素の祖先の要素全てに対してoverflow: visibleを指定する(もしくは、デフォルト値なので何も指定しない)というものです。これは、今回の原因をそのまま解消できるのでsticky要素自体は正しく動作するはずですが、その他の部分で挙動が変わってきます。とくに、レスポンシブなWebページを作成している場合にoverflow: hiddenを指定するのはありがちなので注意が必要です。そのため、この解決方法はそれほど現実的ではありません。

position: fixedやJavaScriptを使用して実現する

stickyは他のposition属性値よりも後から登場した値です。そのため、従来から行われているようにposition: fixedやJavaScriptを使用して同等の処理を実現することを検討するべきでしょう。比べると簡潔さは劣るかもしれませんが、現状ではposition: stickyとその祖先のvisible以外のoverflow属性を両立させるためにはこれしかありません。

個人的には、sticky-sidebarというJavaScriptライブラリを使用するのがおすすめです。このライブラリでは、fixedを使用しているので今回の問題は起きません。オプションとしてcontainerSelectorを指定することで、stickyのような移動範囲の制限が容易に実現できます。JQueryに依存しない形で使用できるのも良い点です。