スクロールしてもサイドバーが追従されるメニューを実現したかったのですが、css の position: sticky
を使うと簡単!てなことでやってみました。
対応ブラウザ問題や position: sticky
がきかない!問題もあると思うので、JavaScript を使う方法もメモしています。
目次
position: sticky の使い方
まずは position: sticky の基本の使い方。
#sidebar {
position: -webkit-sticky;
position: sticky;
top: 0;
}
JavaScript とかを使わずに、これだけシンプルなコードで追従メニューを実現できるのは魅力的ですね。
ただ、サポートしていないブラウザのためにも、以下のような保険をかけた書き方でレイアウトを組む方法もありそうです。
#sidebar {
position: inherit;
}
@supports (position: sticky) or (position: -webkit-sticky) {
#sidebar {
position: -webkit-sticky;
position: sticky;
top: 0;
}
}
これで対応していないブラウザには position: inherit
を、対応しているブラウザには position: sticky
が適用される形となります。
position: sticky が効かない問題
僕が遭遇する position: sticky
が効かない問題の原因ナンバーワンは、先祖要素に overflow: hidden
がかかってるやつです。
メインカラムとサイドバーを float
で組むといった従来のやり方ですね。
この形のレイアウトにする場合、親要素に overflow: hidden
をかけないと後続のマージンが効かなかったり、レスポンシブにした時に謎に画面の右端が切れるといった現象に遭遇します。
ここで注意すべきは、親要素だけでなくさらにその外側など、先祖要素に overflow: hidden
がかかっていると正常な挙動はしません。
なのでカラムレイアウトは Flexbox で組む必要があります。
ただ、僕は個人的には position: sticky
と同様に、対応ブラウザ問題が残るプロパティをあまり使いたくありませんし、がっつりレイアウトが崩れるような箇所は特に使用を避けたいと思ってしまう傾向があります。
おとなしく JavaScript(Sticky Sidebar)を使う方法
「js を使わず css のみで実装してやる!」と意固地にならず、JavaScript に頼る方法も書いてみます。
今回のようなサイドバー追従の実現には『Sticky Sidebar』というスクリプトが評判が良いらしいっぽいので、今回はこちらを試してみることにしました。
Sticky Sidebar のサンプルコード
『Sticky Sidebar』の実装は簡単で、スクロールしてもカクつくこともありませんでした。
<div id="content">
<div id="main">
<!-- #main -->
</div>
<div id="sidebar" class="sidebar-sticky">
<div class="sidebar-sticky-in">
<!-- .sidebar-sticky -->
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/sticky-sidebar@3.3.1/dist/sticky-sidebar.min.js"></script>
<script type="text/javascript">
var sidebar = new StickySidebar('.sidebar-sticky', { // 追従させる要素
containerSelector: '#content', // 親要素
innerWrapperSelector: '.sidebar-sticky-in', // 追従させる要素のインナー要素
topSpacing: 20,
bottomSpacing: 50
});
</script>
「親要素」や「追従させる要素のインナー要素」の命名は任意のようで、これらのオプションを使わなかった場合は自動で生成される仕様のようですが、推奨ではあるようです。
サイドバーで広告とかがずっと付いてくると少し鬱陶しいですが、目次や他ページへのナビゲーションなどを追従させるとユーザビリティが良くなることもあるかもしれませんね。
以上、「position: sticky」や「JavaScript」で追従メニューを実現するためにやってみたことでした。