JavaScriptでヘッダーを縮小させたら何やらチカチカしだした話
はじめに
このサイト、ヘッダーをそろそろ固定化させようかと思いました。
それで、「固定化させるならスクロールでヘッダーを縮小するようにもしよう。」と思ってJavaScriptを設定したのですが、ある一定のスクロール値でヘッダーがチカチカと表示されてしまいました。
要はJavaScriptの設定が悪かったのですが、その際の対応を考えましたので紹介します。
目次
ヘッダーを固定化する
ヘッダーを固定化する方法自体は簡単で、固定化させたい要素のCSSにposition:sticky;
を追加したら良いです。
古くはposition:fixed;
を使うのが一般的だったと思いますが、fixed
だと要素の高さ分全体が上に詰まってしまうので、その調整が必要でした。
sticky
の場合だと高さが保持されるので扱いやすいです。
ただし、CSSにtop
を記述しないと要素が固定化されません。
HTML
<header> <!--ヘッダーの内容--> </header>
CSS
header { position:sticky; top:0; }
できあがったもの
今回はheader
ではなくdiv
にClassを設定しています。
ヘッダーの背景色を赤くしています
ヘッダー
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
テキスト
position:sticky;
で固定化する場合、その兄弟要素まで固定化が保持されます。
つまり、position:sticky;
を設定した要素の親要素までスクロールすると、固定化は解除されるので、CSSを設定する要素には注意して下さい。
ヘッダーを縮小するCSSを作る
「ヘッダーを縮小するCSSを作る」方法も簡単で、「通常のヘッダーの高さを設定したCSS」と「縮小するヘッダーの高さを設定したCSS」の2つのCSSを作れば良いです。
HTML
<header> <!--ヘッダーの内容--> </header>
CSS
header { position:sticky; top:0; height:100px; } .header_run { height:50px; }
あとはJavaScriptで「一定のスクロール値に達したらヘッダーにheader_run
Classを付与する」設定を作れば完成です。
ヘッダーを縮小するJavaScriptを作る(失敗)
JavaScriptで「一定のスクロール値に達したら要素にClassを追加する方法」については別の投稿で紹介したとおりです。
ただ、今回はヘッダー(ブラウザの最上部)からスクロール値を計算すれば良いので、それよりも少し簡単です。
使用したプロパティ
プロパティ | 概要 |
---|---|
window.scrollY | ウインドウ(ブラウザ)の垂直方向(Y方向)にスクロールされたpx値を取得 |
簡単なのですが「ヘッダーの高さを小さくする」場合、このJavaScriptと同じように作成して私は一度失敗します。
折角なので失敗例も紹介します。
JavaScriptの失敗例
私は最初このように記述しました。
window.addEventListener('scroll',function() { const header = document.getElementsByTagName('header'); const scroll_y = window.scrollY; //スクロール値を取得 if(scroll_y >= 100 ) { //スクロール値が100px以上のとき header[0].classList.add('js-header_run'); //Classを付与 } else { //スクロール値が100pxより小さいとき header[0].classList.remove('header_run'); //Classを削除 } });
このように作ると、タイトルにあるようにある一定のスクロール値の範囲で、ヘッダーが高速でチカチカと縮小と拡大を繰り返していました。
どうやらClassの付与と削除が繰り返し行われているようです。
おそらく原因としては以下のような感じだと思います。
- あるスクロール値(スクリプトがちょうど発火する位置)に達する
- CSSが付与されてヘッダーが縮小される
- そのぶん全体のスクロール値が小さくなる
- CSSが削除されてヘッダーが拡大される
- またスクロール値が大きくなってCSSが付与される(以下くりかえし)
という感じなので「スクロール値が通常の高さ – 縮小した高さの間」にいる時にチカチカするのだと考えられます。
そうであれば「Classを所持している場合は、スクロール値が縮小したヘッダーの高さより小さくなった時だけClassを削除すれば良いのではないか」と考え、次のようなJavaScriptに修正しました。
ヘッダーを縮小するJavaScriptを作り直す(成功)
まず「ヘッダーがClassを所持している場合」という判定は要素名.classList.contains('Class名')
のように書きます。
「この条件に合う時」なので== true
と記述します。
そして、この条件に「スクロール値が(縮小した)ヘッダーの高さより小さくなった時」という条件を組み合わせます。
今回は「AかつB」つまりand条件になり、and条件はif ( A && B )
と記述します。
今回使用した主なメソッドは以下のとおりです。
使用したメソッド等
メソッド等 | 概要 |
---|---|
要素名.classList.contains(‘Class名’) | 「要素名」が「Class名」というClassを所持しているかどうかを判定(Class名の前に「.」は不要) |
if ( A && B ) | if文で「AかつB」(AとB両方の条件に合う場合)の処理 |
そして修正したJavaScriptは以下のとおりです。
JavaScript
window.addEventListener('scroll',function() { const header = document.getElementsByTagName('header'); const scroll_y = window.scrollY; //スクロール値を取得 if(scroll_y >= 100 ) { //スクロール値が100px以上のとき header[0].classList.add('js-header_run'); //Classを付与 } else { //スクロール値が100pxより小さいとき(で) //↓header要素に「header_run」がある&スクロール値が50より小さい時 if( header[0].classList.contains('header_run') == true && scroll_y < 50 ) { header[0].classList.remove('header_run'); //Classを削除 } } });
Classを付与して全体のスクロール値が小さくなっても(縮小時のヘッダーの高さが50pxあるため)全体のスクロール値は50px以下にならないので、この設定でClassの付与と削除が繰り返されなくなりました。
そして、スクロール値が50pxより小さくなった時にClassが削除されます。
それで実際にできあがったのが当サイトのヘッダーになります(CSSの設定値やヘッダーの高さは上記の例と多少異なります)