3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

スクロール位置に応じてバーが追従するグローバルメニュー

Last updated at Posted at 2020-06-29

#はじめに
コーディングを行う際、ヘッダーのメニューにある下線をスクロール位置ごとに動かしたかったのですが、躓いてしまったため残したいと思います。
私はコーディング歴も浅く、手探りで実装したので、もしより良い方法があればご教授いただけると幸いです。

#完成形
menu.gif

#コード
下線が追従する基本的な形はこちらを参考にしました。

sample.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Sample</title>

  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css">
  <link rel="stylesheet" href="css/style.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  <script src="js/script.js"></script>
</head>
<body>
  <header class="header">
    <nav id="navigation">
      <ul>
        <li class="current">
          <a href="#">content</a>
        </li>
        <li class="menu-2">
          <a href="#">second-content</a>
        </li>
        <li class="menu-3">
          <a href="#">3rd-content</a>
        </li>
        <li class="menu-4">
          <a href="#">4</a>
        </li>
      </ul>
      <span id="slide-line"></span>
    </nav>
  </header>
  <div class="contents">
    <div class="content" id="content1">ひとつめ</div>
    <div class="content" id="content2">ふたつめ</div>
    <div class="content" id="content3">みっつめ</div>
    <div class="content" id="content4">よっつめ</div>
  </div>
</body>
style.css
header{
  width: 100%;
  height: 30px;
  position: fixed;
}
ul li {
  display: inline-block;
}
a{
  display: inline-block;
  padding: 30px 20px;
  font-size:14px;
  text-decoration:none;
}
#navigation{
  position: relative;
}
#slide-line{
  position: absolute;
  bottom: 0;
  height: 2px;
  background-color:#75C2FF;
  -webkit-transition: all .3s ease;
  transition: all .3s ease;
}

.content{
  height: 700px;
  padding: 80px;
}
.content:nth-child(odd){
  background-color: #f5f5f5;
}
script.js
$(window).load(function(){
  $('nav span').css({
    width: $('nav .current').width(),
    left: $('nav .current').position().left
  });

  $(window).scroll(function () {
    let content2 = $('#content2').offset().top;
    let content3 = $('#content3').offset().top;
    let content4 = $('#content4').offset().top;
    if ($(this).scrollTop() < content2) {
      if ( ! $('header').hasClass("current1") ) {
        $('header').addClass("current1");
        $('header').removeClass("current2 current3 current4");
        $('nav span').animate({
          width: $('nav .current').width(),
          left: $('nav .current').position().left
        });
      }
    }else if ($(this).scrollTop() > content2 && $(this).scrollTop() < content3) {
      if ( ! $('header').hasClass("current2") ) {
        $('header').addClass("current2");
        $('header').removeClass("current1 current3 current4");
        $('nav span').animate({
          width: $('.menu-2').width(),
          left: $('.menu-2').position().left
        });
      }
    }else if ($(this).scrollTop() > content3 && $(this).scrollTop() < content4) {
      if ( ! $('header').hasClass("current3") ) {
        $('header').addClass("current3");
        $('header').removeClass("current1 current2 current4");
        $('nav span').animate({
          width: $('.menu-3').width(),
          left: $('.menu-3').position().left
        });
      }
    }else if ($(this).scrollTop() > content4) {
      if ( ! $('header').hasClass("current4") ) {
        $('header').addClass("current4");
        $('header').removeClass("current1 current2 current3");
        $('nav span').animate({
          width: $('.menu-4').width(),
          left: $('.menu-4').position().left
        });
      }
    }
  });
});

#仕組み
まずメニューバーが動く仕組みについてですが、animateメソッドを使って横幅と位置を指定することで動きをつけています。
こちらの詳細は参考サイトにございますのでご覧ください。

let content2 = $('#content2').offset().top;
let content3 = $('#content3').offset().top;
let content4 = $('#content4').offset().top;```
次にスクロールによる、スクロールをした時の区切りとなる要素の位置を上記で定義します。
以下のif文に関しての説明です。
現在のスクロール位置が特定の区切りの中(例えばcontent2の中)にいるか、かつheaderが特定のクラス(前の例えだとcontent2というクラス)を持っていないとメニューバーが動くという仕組みです。

#悩んだこと
今回はheaderのクラスのつけ外しを行うことでうまく動かしているのですが、これをする前はうまくいっていませんでした。
console.logなどで確かめてみるとわかるのですが、scrollアクションは少しのスクロールで何回も発火するため、その度にanimateメソッドが読み込まれ非常に処理が重くなってしまいました。
そこで私は、animateメソッドが読み込まれるのをスクロール位置が切り替わった時のみにしたいと考え、クラスの有無を条件式としてあげることで重くなることを防ぐことができました。

#おわりに
最後までご覧いただきありがとうございます。
この方法は初心者の私が考えたやり方のため、無理のある記述の可能性があります。
ぜひ有識の方がいらしたらご意見くださると幸いです。
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?