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_runClassを付与する」設定を作れば完成です。

ヘッダーを縮小する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の設定値やヘッダーの高さは上記の例と多少異なります)