CSSのposition stickyが効かない原因と解決方法【html/bodyのoverflowが原因だった】

Web関連·
サムネイル画像

Webサイトで「追尾メニュー」「サイドバー目次」などを実装する際、 position: sticky を使ったのに なぜか全く追尾しない という経験はないでしょうか。

本記事では、実際に私がハマった事例をもとに、

  • sticky が効かない本当の原因
  • DevTools(開発者ツール)での正しい確認方法
  • html / body の overflow が原因だったケースの解決策

を、再現手順付きで解説します。


position: sticky が効かないときにありがちな勘違い

まず、以下のような CSS を書いても追尾しないケースがあります。

.category-toc {
  position: sticky;
  top: 100px;
}

よくある勘違いは次のようなものです。

  • position: sticky を指定したのに動かない
  • top も指定している
  • 親要素に overflow: hidden は付けていないつもり

それでも動かない場合、sticky 自体は正しく当たっているのに、構造上殺されている 可能性があります。


まず確認すべきこと(DevToolsでのチェック方法)

Chrome(Edge)で DevTools を開き、Console タブで以下を確認します。

const el = document.querySelector('.category-toc');

getComputedStyle(el).position
getComputedStyle(el).top
getComputedStyle(el).overflow

メモ

初めての方は allow pasting を手動で入力すればOK

正常な状態の目安

position: "sticky"
top: "100px"
overflow: "visible"

ここが正しければ、sticky指定そのものは失敗していません

それでも追尾しない場合、次を疑います。

stickyが効かない最大の原因:html / body の overflow

今回の原因は html と body の overflow 設定でした。

Consoleで調べると、以下のような状態になっていました。

{
  scrollingElement: 'html',
  htmlOverflow: 'hidden auto',
  bodyOverflow: 'auto'
}

これは実質的に:

  • html:overflow-x: hidden; overflow-y: auto
  • body:overflow: auto

という スクロールコンテナが二重になっている状態です。

なぜ html / body の overflow が sticky を壊すのか

position: sticky は、

  • 一番近いスクロールコンテナ
  • もしくは viewport

を基準に動作します。

しかし、

  • html がスクロール
  • body もスクロール可能
  • さらにラッパー要素が存在

という構成になると、sticky の基準が不安定になり、 結果として「見た目上まったく追尾しない」状態になります。

解決策:スクロールは html に任せ、body は通常フローに戻す

最も安定した解決策は以下です。

html {
  overflow-x: hidden;
  overflow-y: auto;
}

body {
  overflow: visible;
}

ポイント

  • 縦スクロールは html に一本化
  • body を overflow: auto にしない
  • 横スクロール防止の overflow-x: hidden はOK

この設定を入れた瞬間、 それまで動かなかった sticky が 即座に正常動作しました。


一時的に確認したい場合(Consoleでのテスト)

CSSを編集する前に、Consoleで一時的に試すこともできます。

document.documentElement.style.overflowY = 'auto';
document.documentElement.style.overflowX = 'hidden';
document.body.style.overflow = 'visible';

これで追尾するなら、原因は overflow 設定で確定です。

よくある「再発原因」への注意

以下のような実装があると、再び sticky が壊れます。

  • モーダル実装で常時 html { overflow: hidden }
  • レイアウト都合で body { overflow: auto }
  • height: 100vh + overflow 制御のラッパー

モーダル用にスクロールを止めたい場合は、 通常時は auto、モーダル時だけ hidden にするのがおすすめです。

html {
  overflow-y: auto;
  overflow-x: hidden;
}

.modal-open html {
  overflow: hidden;
}

まとめ:stickyが効かないときはここを疑う

  • positiontop が正しくても安心しない
  • 親要素だけでなく html / body の overflow を必ず確認
  • スクロールコンテナは 1つに統一する

sticky が効かない問題は CSS の書き方よりも、 「どこがスクロールしているか」 が原因であることが非常に多いです。

同じことで悩んでいる方の参考になれば幸いです。

🔥 同じカテゴリーの記事
最終更新日

広告