このページの本文へ

jQuery不要!センスのいいナビゲーションをJSでサクッと実装する方法

2017年06月15日 11時23分更新

文●Albert Senghor

  • この記事をはてなブックマークに追加
本文印刷
WPJでも使っているアニメーション付きのスティッキーナビゲーションメニュー。いまならjQueryや専用ライブラリーに頼らなくても、たった数行のJavaScriptで実装できます。

Webページのナビゲーションメニュー作成には、考えるべきことがたくさんあります。どこに配置するか、スタイル、レスポンシブのデザイン、アニメーションなど。さらにセンスよく実装したいですよね。ここまで読んで、jQueryプラグインを連想したかもしれませんが、その必要はありません。ほんの数行のコードで簡単に実現できるのです。

この記事では、素のJavaScript、CSS、HTMLでアニメーション付き「スティッキーナビゲーションメニュー」の作成方法を紹介します。ページをスクロールダウンすると邪魔にならないメニューが上にスライドし、スクロールバックすると、スタイリッシュなシースルー効果で画面に戻ります。MediumHacker Noonなどの人気サイトで使われている技術です。

この技術をデザインに、うまくいけば効果的に活かせるようになります。気の早い人のために、この記事の最後にデモを用意しました。

スティッキーナビゲーションメニュー:基本的なHTML構造

これから扱うHTMLコードのスケルトンを次に示します。特筆すべきことはありません。

<div class="container">
  <div class="banner-wrapper">
    <div class="banner">
      <div class="top">
        <!-- Navbar top row-->
      </div>
      <div class="nav">
        <!-- Links for navigation-->
      </div>
    </div>
  </div>

  <div class="content">
    <!-- Awesome content here -->
  </div>
</div>

少しスタイリングする

メインの要素にスタイルをいくつか加えます。

メインコンテナー

元のブラウザースタイルを削除し、コンテナーの幅を100%に設定します。

*{
  box-sizing:border-box;
  padding: 0;
  margin: 0;
}

.container{
  width: 100%;
}

バナーコンテナー

ナビゲーションメニューまわりのラッパーです。スクロールしても追尾するナビゲーションメニューで、スライドすると隠したり表示したりします。コンテンツのトップに現れるようにz-index値を与えています。

.banner-wrapper {
  z-index: 4;
  transition: all 300ms ease-in-out;
  position: fixed;
  width: 100%;
}

バナーセクション

ナビゲーションメニューが含まれます。ページが上下にスクロールしたときの位置や背景色の変化にCSSのtransitionプロパティでアニメーションをつけます。

.banner {
  height: 77px;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  background: rgba(162, 197, 35, 1);
  transition: all 300ms ease-in-out;
}

コンテンツセクション

This section will contain a background image and text. We will add a parallax effect to this part of the page in a later section of the article.

背景のイメージとテキストが含まれます。あとでパララックス効果を加えます。

.content {
  background: url(https://unsplash.it/1400/1400?image=699) center no-repeat;
  background-size: cover;
  padding-top: 100%;
}

メニューにアニメーションをつける

最初は、スクロールイベントにイベントハンドラーを付与して、ユーザーのスクロールに応じてメニューを隠したり表示したりします。また、IIFEですべてを囲んで、同じページで走っているほかのコードとのクラッシュを避けます。

(() => {
  'use strict';

  const handler = () => {
    //DOM manipulation code here
  };

  window.addEventListener('scroll', handler, false);
})();

初期値を設定する

ユーザーがページをスクロールした距離を表現するrefOffset変数を使います。ページがロードされたら、値を0に初期化します。メニューの高さを格納するbannerHeight変数を使い、.banner-wrapperと.bannerのDOM要素への参照も必要です。

let refOffset = 0;
let visible = true;
const bannerHeight = 77;

const bannerWrapper = document.querySelector('.banner-wrapper');
const banner = document.querySelector('.banner');

スクロールの方向を決める

スクロール方向によってメニューを隠したり、表示したりします。

変数newOffsetから始めます。ページがロードされると、この値がwindow.scrollY(ドキュメントが現在、垂直方向にスクロールされたピクセル数;初期値は0)に設定されます。ユーザーがスクロールすると、newOffsetは増えたり、減ったりします。これがbannerHeightに格納された値よりも大きくなると、メニューが画面の範囲外に出たと分かります。

const newOffset = window.scrollY;

if (newOffset > bannerHeight) {
  // Menu out of view
} else {
  // Menu in view
}

下方向にスクロールすると、newOffsetrefOffsetより大きくなり、ナビゲーションメニューを上にスライドさせ非表示にします。下方向にスクロールすると、newOffsetrefOffsetより小さくなり、ナビゲーションメニューをシースルー効果付きで画面に表示します。ユーザーがどのくらいスクロールしたかを記録するために、refOffsetの値をnewOffsetの値で更新します。

if (newOffset > bannerHeight) {
  // Menu out of view
  if(newOffset > refOffset) {
    // Hide the menu
  } else if (newOffset < refOffset) {
    // Slide menu back down
  }

  refOffset = newOffset;
} else {
  // Menu in view
}

メニューアニメーションを付加する

最後に、メニューを見せたり隠したりするために、animateInanimateOutメソッドを加えます。また、ページのトップに達したら、シースルー効果をメニューから削除するのを忘れてはいけません。

if (newOffset > bannerHeight) {
  if (newOffset > refOffset) {
    animateOut();
  } else {
    animateIn();
  }

  refOffset = newOffset;
} else {
  banner.style.backgroundColor = 'rgba(162, 197, 35, 1)';
}

アニメーションを実行する関数です。

function animateOut() {
  bannerWrapper.style.transform = `translateY(-${bannerHeight}px)`;
  bannerWrapper.style.msTransform = `translateY(-${bannerHeight}px)`;
  bannerWrapper.style.webkitTransform = `translateY(-${bannerHeight}px)`;
  bannerWrapper.style.MozTransform = `translateY(-${bannerHeight}px)`;
  banner.style.background = 'rgba(162, 197, 35, 0.6)';
}

function animateIn() {
  bannerWrapper.style.transform = 'translateY(0px)';
  bannerWrapper.style.msTransform = 'translateY(0px)';
  bannerWrapper.style.webkitTransform = 'translateY(0px)';
  bannerWrapper.style.MozTransform = 'translateY(0px)';
  banner.style.background = 'rgba(162, 197, 35, 0.6)';
}

CSSクラスを必要に応じて消去したり加えたりしながら利用することが考えられますが、ここではJavaScriptで実装しました。

デモ

実際に動いているメニューのデモです。

最後に

素のJavaScriptを数行書くだけでアニメーション付きのナビゲーションメニューをデザインする方法を紹介しました。jQueryは使いません。スクロールダウンすると、メニューはスライドして消え、スクロールアップするとシースルー効果とともにスライドしながら画面に再登場します。この動作は、垂直方向のスクロールをモニターし、必要に応じてDOM要素にCSS変換を適用することで実現されます。手作りの解決法なので、要求や仕様に応じて、意のままにデザインができます。

本記事はVildan Softicが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者のみなさんに感謝します。

(原文:Create an Animated Sticky Navigation Menu with Vanilla JavaScript

[翻訳:関 宏也/編集:Livit

Web Professionalトップへ

WebProfessional 新着記事