6月第2週にお送りしているQuery Week。jQueryでタブで切り替えできるメニューを作成!メニュー数が増えても対応できる作り方・ポイントを抑えるに引き続き、今日は「スクロール途中でヘッダーメニューを固定させる」実装方法について紹介したいと思います!
メニューが固定される時に、にゅるっとしたアニメーションで動きをつけるための作り方についても紹介したいと思います!
目次
今回jQueryで作りたいものをサンプルコードを交えて紹介・スクロールすると途中でヘッダーメニューが固定
今回もまず完成形イメージのサンプルコードを掲載したいと思います!
jsFiddleというサービスを使っている関係で、表示部分の画面がちょっと小さくなっているかと思いますが、その点はご了承ください・・・!
スクロールすると、ヘッダーメニューに該当する部分が途中で固定されているのがわかるかと思います!
また、メニューが固定された際にはにゅるっとしたアニメーションでヘッダーメニュー部分が表示されているのも見てとれます。
今回の作成物、イメージいただけましたでしょうか!
jQueryでスクロールして途中からヘッダーを固定させるためのコードのポイント
それではここからは、jQueryでスクロールして途中からヘッダーを固定させるためのコードのポイントをご紹介したいと思います!
ポイント1・スクロールした時に何かをするイベントの書き方を理解する
jQueryでスクロールして途中からヘッダーを固定させるためのコードのポイントその1は、「スクロールした時に何かをするイベントの書き方を理解する」ということです。
今週のjQuery Weekでご紹介した4つのUIは、どれも「クリックした時にjQueryによって何かを動かす」というものになっていました。
今回ご紹介している内容は、スクロールした時にjQueryで何かをするというものになっています。どのように書けばよいのでしょうか??
ここで出てくるのが「scroll」イベントになります!
scrollイベントは文字通り、Webサイト上のどこかしらがスクロールした時に(基本的にはブラウザをスクロールさせた時に何かをさせることが多いですね)、jQueryを使って特定の動きを実現することができるものになっています!
そして「ブラウザ」をスクロールさせた時にという部分においては$(window)
というセレクタが使用されます。
以上をまとめると
$(window).on('scroll', function(){
/* スクロールされた時にやりたいことをここに書く */})
と記述することで、ブラウザがスクロールされた時にfunction(){}の中に書かれたコードを実行させることができるようになるわけなんですね!
なお、今回のサンプルコードにおいては
$(window).on('load scroll', function(){
/* スクロールされた時にやりたいことをここに書く */})
という形で、イベントを設定する部分に「load scroll」という2つが指定されています。
今回実現したい内容の1つとして「Webサイトのどの地点までスクロールされているかによってメニュー部分を固定させるか、固定させないか」というのがありました!
ですので、loadつまりページが読み込みされた瞬間にも、メニューを固定させるかさせないかを判断するためのプログラムを実行させる必要があるわけなんですね!
jQueryのイベント設定(プログラムを実行させたいタイミング)においては、半角スペースで区切ることで、イベントを複数設定させることができます!
ポイント2・どれだけスクロールしたのか&特定のHTMLがページ最上部からどれだけ離れた位置にあるのかをプログラム上で扱うための方法を知る
ポイントその2です。その2は、どれだけスクロールしたのか&特定のHTMLがページ最上部からどれだけ離れた位置にあるのかをプログラムで扱うための方法を知るということです。
ヘッダーナビゲーションを固定させるかさせないか、判断するための方法を画像でまとめてみました。
まずあらかじめヘッダーナビゲーションの下端がページの1番上から数えて何pxの距離にあるかを計測しておきます。(これをAとします)
次に、スクロールするたびにページの1番上からどれだけスクロールされたのかを都度計測する仕組みを作っておきます。(これをBとします)
こうしておけば、スクロールする度に実行されるプログラムにおいて「AとBのどちらか大きいのか」を常に比較するようにして、
- A <= Bだったらヘッダーメニューを固定させるようにする
- A > Bだったらヘッダーメニューを固定させないようにする
ようにプログラムを組んでおけば良いというわけなんですね!
上記で紹介したAとBについてですが、ちゃんとjQuery(JavaScript)で計算する方法が用意されています!
jQueryで用意されているoffset()というものを使用すると、ページの1番上から指定したHTMLタグが何pxの距離に配置されているのかをデータとして取得することができます!
ヘッダーメニューの下端=その下のHTMLタグの上端と考えることができるので、今回は$(’.main’).offset().top
とすることで、必要な情報を取得することができます。
さらにscrollTop() というものを使うと、その時どれくらいの量がスクロールされたかをデータとして取得することができます。
$(window).scrollTop()
とすると、そのWebサイト上でどれだけスクロールしたのかデータとして取得することができるので、お決まり文句みたいなもので覚えておきましょう!
const $main = $(".main");
const $distance = $main.offset().top; /*これがA*/
const $scrollVal = $(window).scrollTop(); /*これがB*/
ポイント2に該当するコードは、上記の部分になります!
ポイント3・基準位置よりスクロール量が多いか少ないかで実行したいプログラムを変える
さて、ポイント2までで
- ヘッダーメニューを固定させるかさせないかを判断する基準位置
- ページ上でどれだけスクロールしたかを計測するためのスクロール量
をデータとして取得することができました。あとはこの2つをスクロールする度に比較して、
- A <= Bだったらヘッダーメニューを固定させるようにする
- A > Bだったらヘッダーメニューを固定させないようにする
ためのプログラムをそれぞれ実行するだけですね!
こういったときのように「その時の条件によって実行したいプログラムを切り分けしたい」ときに使用するのがif文になります!
上記に掲載した画像では、条件によって実行したいプログラムのパターンが3つ以上ある場合のことも考えて「else if」も含めて紹介しましたが、else ifはなくてもOKです!
今回のサンプルプログラムでいうと
if($scrollVal > $distance){
$homeHeader.addClass("fix");
}else{
$homeHeader.removeClass("fix");
}
上記コード部分になります!
固定させるかさせないかは、jQueryを使ったハンバーガーメニューボタン開閉の動きの作り方!色々なUI作成に応用できる仕組みについても理解しよう!でも紹介したようなやり方を踏襲しています!
要するに、CSSにできるところはお任せして、jQueryではfixというclassの付け替えをaddClass()やremoveClass()で表現するという、最小限のコード量にとどめているわけですね!
にゅるっと出てくるためのアニメーション部分を実装
さて、ここまでの内容だけでも問題なく「スクロール途中でヘッダーメニューを固定させる」ことを実装することができるようになっているのですが、せっかくですので、アニメーションもつけてあげるとよりカッコよくなりますし、固定されたことが視覚的にもわかりやすくなりますよね!
今回のようなにゅるっとアニメーションは、CSSに担当してもらいます!
CSSの上記コードの部分が、アニメーションの内容を定義および実行しているところです!
通常時はアニメーションをさせる必要がないので、fixというclassがヘッダーメニューのHTMLについた時だけアニメーションが実行するように、.header.fix
というセレクタに対してCSSのanimationプロパティを設定しています!
CSSのanimationプロパティを使うと、細かいアニメーション表現を実装することができます。
しかし、細かければ細かいほど、1行でアニメーションの内容を表すことは難しくなります。
ですので、CSSには、「keyframes」という、具体的にアニメーションを設定するための仕組みが用意されています!
アニメーションの考え方としては上記の通りです!
ヘッダーメニューが固定された瞬間に一旦margin-top: -64px;を設定し、その後にmargin-top:0;に戻すようにすることで、自然と「上からにゅるっと」したアニメーションを実装することができるようになります!
@keyframes nyuru {
0%{
margin-top: -64px;
}
100%{
margin-top: 0;
}
}
CSSアニメーションの具体的な内容を定義した部分を抜粋してみました!
0%や100%というのは、アニメーションにかける時間(今回の事例でいうと0.5sつまり0.5秒)の中で、経過時間を%の単位で表しているという意味になります!
アニメーションにかかる時間が0.5sであれば
- 0%・・・アニメーションが始まるとき
- 50%・・・0.25秒
- 100%・・・0.5秒(アニメーション終了)
となります!
ヘッダーメニューの中にコンテンツが隠れないようにするための配慮
最後にちょっとした配慮を加えた部分を紹介します!
if($scrollVal > $distance){
$homeHeader.addClass("fix");
$main.css("margin-top", $navH);
}else{
$homeHeader.removeClass("fix");
$main.css("margin-top",0);
}
上記コードにおいて$main.css("margin-top", $navH);
だったり$main.css("margin-top",0);
という箇所があるかと思います。
ヘッダーメニューに対してposition:fixedを指定すると、ヘッダーメニューがいわゆる宙に浮いた状態になって、後に続くコンテンツ(HTML)の上に重なる状態になります。
特に何も対処をしないと、ヘッダーメニューを固定した瞬間にヘッダーメニューの高さ分だけ、後に続くコンテンツが上にずれこんでしまい、メニューが固定された瞬間に動きがガタッとカクカクしてしまう状態になります。
これを防ぐために、$('.main')
に対してヘッダーの高さ分だけmargin-topを設定してあげることによって、スムーズに固定されるようにしているわけなんですね!
これで、全てが完成した形になります!
まとめ
ということで今回は、「jQueryでスクロールして途中からヘッダーを固定させる!にゅるっと出てくるアニメーションの作り方も紹介」という内容でブログ記事を紹介させていただきました!
今日の内容は少し難易度があがり、説明する内容もいつも以上に多かったため、僕自身も記事を書くのに苦労してしまいましたが、参考になれば幸いです!
明日は、jQuery Week最後の記事、プラグインについて見てみたいと思います!