よく色んなサイトで見る、スクロールに合わせてグローバルメニューが移動する機能を実装したい。と思っている人にその方法について解説していきたいと思います。
とは言っても簡単で、CSSと少しのJavaScriptだけで実装できます。
早速解説していきましょう。
グローバルメニューが画面の一番上にある場合
この場合はJavaScriptを使うこともなく、CSSのみで実装可能です。
まずはヘッダーが固定されていないデフォルトの状態をコーディングしていきます。
<!-- ヘッダー -->
<header>
<div class="header_wrap">
<h1>Site Name</h1>
<nav id="nav">
<ul>
<li><a href="#">HOME</a></li>
<li><a href="#">HOME</a></li>
<li><a href="#">HOME</a></li>
<li><a href="#">HOME</a></li>
<li><a href="#">HOME</a></li>
</ul>
</nav>
</div>
</header>
<!-- メイン -->
<main>
<div class="contents"></div>
</main>
/* ヘッダー */
header{
background-color: black;
}
.header_wrap{
display: flex;
max-width: 1000px;
padding: 5px 0;
margin: 0 auto;
justify-content: space-between;
align-items: center;
color: white;
}
nav{
ul{
margin: 0;
text-align: center;
li{
display: inline-block;
padding: 5px 10px;
a{
color: white;
font-weight: bold;
}
}
}
}
/* メイン */
.contents{
height: 5000px;
background-color: red;
}
グローバルメニューが一番上にある場合はヘッダーに含まれていることが多く、また、ヘッダーごとスクロールに合わせて移動することがほとんどなので今回そのように実装していきます。
また、ヘッダーが移動しているか分かりやすいようにmain
タグの中にcontainer
クラスを与えたdiv
タグを用意して、その要素に対してheight:5000px
を指定しています。これでスクロールできるだけの十分な高さを確保できます。
現段階でスクロールすると、ヘッダーが置いてきぼりとなり次第に見えなくなってしまう状態だと思います。
これをスクロールさせても画面の一番上にヘッダーが固定された状態にしていきます。
結論としてはpositon
プロパティにfixed
を指定してあげます。
header{
background-color: black;
/* 追加 */
position: fixed;
width: 100%;
top: 0;
z-index: 1;
}
ただ、position: fixed
を指定しただけではデザインが崩れてしまいます。
というのもそれまで親要素いっぱいまで広がっていた該当要素のwidth
プロパティがposition: fixed
を与えることで該当要素の子要素のwidth
分までのwidth
になってしまいます。
上記の問題を解決するために該当要素にwidth: 100%
を指定してあげます。
また、画面の一番上に固定させるためにtop: 0
の指定と一番前に表示されるようにz-index: 1
を指定します。
これでスクロールに合わせて、ヘッダーがそのままの位置で移動してくれるようになりました。
グローバルメニューが画面の途中にある場合
グローバルメニューが途中に存在する場合は上記の方法ではうまく実装することができません。
まずはグローバルメニューがスクロールに合わせて移動しないデフォルトの状態をコーディングし確認しましょう。
<!-- ヘッダー -->
<header>
<div class="header_wrap">
<h1>Site Name</h1>
<nav id="nav">
<ul>
<li><a href="#">HOME</a></li>
<li><a href="#">HOME</a></li>
<li><a href="#">HOME</a></li>
<li><a href="#">HOME</a></li>
<li><a href="#">HOME</a></li>
</ul>
</nav>
</div>
</header>
<!-- メイン -->
<main>
<div class="contents"></div>
</main>
/* ヘッダー */
.header_wrap{
text-align: center;
color: red;
h1{
margin-bottom: 0;
}
}
/* グローバルメニュー */
#nav{
background-color: black;
li{
display: inline-block;
padding: 5px 10px;
a{
font-size: 20px;
color: white;
}
}
}
/* メイン */
.contents{
height: 5000px;
background-color: red;
}
HTMLのコードは先ほどとほとんど同じですね。JavaScriptで扱いやすいようにnav
タグにid
属性の値としてnav
を与えています。また、CSS(Sass)のコーディングを変えて、デザインを変更しています。
先ほどのものはヘッダー全体をスクロールに合わせて移動させていましたが、今回は背景が黒色のグローバルメニューの部分だけを移動させます。
今回、移動させたい要素が画面の途中にあるため、先ほどのようにいきなり画面の上部に固定するようにしてしまうとデザインが崩れてしまいます。
デザインが崩れないようにスクロールに合わせて移動させるには、スクロールして画面上部と移動させたい要素(今回はグローバルメニュー)の上部が重なるときに移動を開始するようにすることで実現したいことができます。
これを実現するにはCSSだけではなく、JavaScript(jQuery)も使っていきます。
まずはコーディングを行い、解説していきます。
/* 追記 */
.fixed{
position: fixed;
top: 0;
width: 100%;
z-index: 1;
}
// ヘッダー追従
var offset = $('#nav').offset();
$(window).scroll(function(){
if($(this).scrollTop() > offset.top){
$('#nav').addClass('fixed');
}else{
$('#nav').removeClass('fixed');
}
});
まず、CSSに画面上部に要素を固定するためのfixed
クラスを用意します。
offsetメソッドで#nav
要素の表示位置を取得し、変数offset
に代入します。
その後、window
に対してスクロールイベントを設置しています。スクロールイベントでは画面縦のスクロール量が#nav
要素表示位置の上部を超えた場合に、#nav
要素にfixed
クラスを与えて、画面縦のスクロール量がそれ以下の時にはfixed
クラスを外すようにしてあげます。
こうすることで画面上部がグローバルメニューの上部の位置と重なるときにはスクロールしても画面上部にグローバルメニューが固定されるように、スクロールに合わせて移動するような動きが実装出来ました。
まとめ
CSSとJavaScript(jQuery)のみで簡単に実装出来ましたね。また、コピペでも実装できるので、ぜひ自分のサイトなどでも実装してみてください。