こんにちは!フリーランスエンジニアののせっち@nosecchi01です。
下スクロール時はヘッダーを隠し、上スクロールで出現するヘッダーメニューの作り方のご紹介です。
通常の作り方なら沢山のブログ記事がありますが、iPhone(iOS)対応の記事はない印象でした。
よく見る書き方とその問題点とは?
よく見る書き方は下記です。
let startPos = 0;
let winScrollTop = 0;
const Header = $('#header');
$(window).on('scroll',function(){
winScrollTop = $(this).scrollTop();
if (winScrollTop >= startPos) {
$(Header).addClass('is-hide');
} else {
$(Header).removeClass('is-hide');
}
startPos = winScrollTop;
});
.l-header {
align-items: center;
background: #fff;
display: flex;
height: 58px;
width: 100%;
}
.l-header--fixed {
left: 0;
position: fixed;
top: 0;
transition: transform 0.3s;
width: 100%;
z-index: 999;
}
.l-header.is-hide {
transform: translateY(-100%);
}
ほぼ他の記事からの引用ですので解説は省略します。
ですが、このままでは下記の問題が…。
iOSではページトップでヘッダーが隠れてしまう…
先ほど紹介したコードではiOSで致命的なバグが出ます。
ページ最上部に来たときにヘッダーが非表示になってしまいます。
原因は、iOSの仕様です。
iOSの仕様
- 上スクロールでページ最上部に来ると、最後バウンスする。(最上部より更に上に行く感じ)
- バウンスして戻ってくるときの挙動が下スクロール判定となる。
- 結果、ページトップではヘッダーが非表示になってしまう。(最後スクロールダウンだから)
iOS対応のコードはこちら
条件を一つ書き足せばOKです。
let startPos = 0;
let winScrollTop = 0;
const Header = $('#header');
$(window).on('scroll',function(){
winScrollTop = $(this).scrollTop();
if (winScrollTop >= startPos && winScrollTop > 100) { // ここにコードを追加
$(Header).addClass('is-hide');
} else {
$(Header).removeClass('is-hide');
}
startPos = winScrollTop;
});
winScrollTop > 100 を書き足しました。
- StartPos: 直前までのスクロールの値
- winScrollTop:現在のスクロール量
なので、現在のスクロール量が直前までのスクロール量より多い、かつ、現在のスクロール量が100スクロールより大きい場合、ということになります。
もっと簡単に言うと、
ページ最上部から100スクロール以内では、is-hideクラスを付けないよ、という条件を追加しました。
これで、iOSでのバウンスする問題を回避できます。
ほんの100スクロールですが、追従固定ヘッダーの状態になりますので、気になる方は100の値を調整してみてください。
UX的なデメリットはないし、あまりギリギリは狙わない方がいいと思い僕は100としました。
まとめ
- よく見る上スクロールで表示、下スクロールで非表示のコードではiOSで不具合が出る。
- iOS対応のためには条件を一つ追加すればOK!
- iOSは意外と曲者です。