ヘッダーの追従固定化（jQuery利用・keyframes利用）

お世話になっております。コウヤです。

先日、Webデザイン・コーディングの中級卒業課題を終え、プロの方にOKをいただきました！
続けて、PHPやWordpressあたりに手を付けようと思いますが、その前に、今回の課題で得たスキルをまとめていきたいと思います。

今回はページ内を移動した際に、ヘッダーが固定化されるようなデザインを考えていこうと思います。

## 追従ヘッダーとは
以下のように、ヘッダーがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/1d0513a6-8dc5-6cbe-6891-32908ae520c6.png)

よく見かけるデザイン化と思いますが、ページ内スクロールをすると、以下のようにヘッダーが表示され、それを追従して固定化ように表示させることを考えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/37af5cfd-bd33-bebd-ad82-9458028d10e1.png)

今回の作成において、スマートフォンによるレスポンシブ化は考慮しておりません。PCのみで考えます。（コードが長くなるため）

## ヘッダー部分の作成
まずは追従させることは考慮せず、以下のヘッダー部分の作成をしていきます。（下記の赤枠の箇所）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/ee113a52-05d7-b038-c5ed-f4c7c47c529a.png)


追従機能を確認するため、HTMLでは「MissionVision」という形で **xxxxxxxxxx** という文字も入れております。
```.index.html
    <!--first view(ヘッダメニュー)-->
    <header class="header">
        <div class="ly__wrapper_head">

            <div class="head__menu">
                <ul class="head__menu_area">
                    <li class="menu__item"><a href="#MissionVision">メニュー1</a></li>
                    <li class="menu__item"><a href="#CEO">メニュー2</a></li>
                    <li class="menu__item"><a href="#JobList">メニュー3</a></li>
                </ul>
            </div>      
        </div>
    </header>

<!--当社のMissionVision-->
   <main id="MissionVision">
        <div class="ly__wrapper_head">
            <div class="MissionVision__title_area">

                <h1>xxxxxxxxxxxxxxxxxxxxxxxxxxx</h1>
            </div>


            <div class="MissionVision__guide fadein">

                <h1>xxxxxxxxxxxxxxxx</h1>
                <p class="MissionVision__guide_sentence">
                    xxxxxxxxxxxxxxx
                    </p>
            </div>
            
            <div class="MissionVision__guide _reverse fadein">
                <p class="MissionVision__guide_sub_title">

                </p>
                <h1>xxxxxxxxxxxxxxxx
                </h1>
                <p class="MissionVision__guide_sentence">xxxxxxxxxxxxxxxxxxxxxxxxxxxx</p>
            </div>
        </div>
    </main>
```

```style.css
  .header {
    border:1px solid red;
    height: 100px;
  }
  .head__menu {
    display: block;
  }

  .head__menu {
    margin:0 auto;
    line-height: 100px;
  }

  .head__menu_area {
    display: flex;
    flex-direction: row;
    align-items: center;
  }
  .head__menu_area li:not(:last-of-type) {
    margin-right: 25px;
  }
  .head__menu_area .menu__item a {
    color: red;
    font-family: Noto Sans JP;
    font-size: 12px;
    font-style: normal;
    font-weight: 400;
    line-height: normal;
  }


#MissionVision {
  margin-top: 191px;
  height: 1243px;
  background-image: url(../img/mission-bg.png);
  background-repeat: no-repeat;
  background-position: bottom center;
}
#MissionVision .MissionVision__title_area {
  text-align: center;
  margin-bottom: 132px;
}
#MissionVision .MissionVision__title_area .MissionVision__sub_title {
  display: inline-block;
  width: 98px;
  height: 12px;
  flex-shrink: 0;
  margin-bottom: 9px;
}
#MissionVision .MissionVision__title_area h1 {
  color: #333;
  font-family: Noto Sans JP;
  font-size: 20px;
  font-style: normal;
  font-weight: 700;
  line-height: normal;
}
```

このCSSの下にさらに以下のコードを追加します。
```style.css
#MissionVision .MissionVision__title_area .MissionVision__sub_title {
/*上記と同じ*/
}

#MissionVision .MissionVision__title_area h1 {
/*上記と同じ*/
}

/*追従header*/
.header--sticky {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  visibility: visible;
  animation: slideDown 0.3s ease-in-out;
  background-color: #ccccff;
  z-index: 20;
}

.header--sticky .menu__item a {
  color: red;
}

@keyframes kf-slideDown {
  0% {
    transform: translateY(-100%);
  }
  100% {
    transform: translateY(0%);
  }
}

```

説明します。**.header--sticky**というクラスはHTML上には記載はないですが、後ほどjQueryでそのクラスを追加するという処理を行います。

```
.header--sticky {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  visibility: visible;
  animation: kf-slideDown 0.3s ease-in-out;
  background-color: #ccccff;
  z-index: 20;
}
```

追従操作をさせるため、**position**ではfixedを設定しています。
今回重要なのは、**animation**の箇所です。この**animation**の箇所に記載のある**kf-slideDown**は勝手につけた名前で、これが以下の**keyframes**にかかってきます。

```
@keyframes kf-slideDown {
  0% {
    transform: translateY(-100%);
  }
  100% {
    transform: translateY(0%);
  }
}
```

この時点ではまだ動かないのでご注意ください。

ここでは何をしているかというと、**animation**で0.3sと指定していますが、この0.3秒の間に、最初の0%（0秒時点）ではヘッダはY軸（縦方向）に-100%の位置に隠れており、最後の100%（0.3秒時点）では0%の位置にヘッダがある状態となります。

【最初の0%時点】
紫背景（緑枠）のヘッダは-100%の位置に隠れている状態
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/f3782362-0bd4-1741-1ace-460628f94260.png)


【最後の100%の時点】
紫背景は0%の位置に表示される状態
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/c665454c-a1c7-5606-5846-f1ce579441f3.png)


これは今回、0%と100%で行ったが、間に50%を入れることも可能ですので試してみてください。

## jQueryで動作させる
それではjQueryで動作させます。以下のようにコードを書きます。

```.script_JQ.js
/*追従ヘッダー */
window.addEventListener('scroll', function() {
	const header = document.querySelector('.header');
	const headerHeight = header.offsetHeight; // ヘッダーの高さを取得
	
	if ($(this).scrollTop() > 100) {
	  header.classList.add('header--sticky');
	  document.body.style.marginTop = headerHeight + 'px'; // コンテンツにヘッダーの高さ分の余白を設定
	} else {
	  header.classList.remove('header--sticky');
	  document.body.style.marginTop = '0'; // コンテンツの余白をリセット
	}
  });

```

まず、addEventListenerではscrollしたら動作するといった処理を設定しています。
**if**の箇所で「スクロールの位置が100px」を超過したら、CSSで指定した**.header--sticky**をHTML内の.headerクラスの箇所に追加（add）します。
```
$(this).scrollTop() > 100
```

またもし100px未満の位置にスクロールがあった際には、marginTopの位置を0にして、headerコンテンツの余白を0にしています。


##コードまとめ
```index.html

    <!--first view(ヘッダメニュー)-->
    <header class="header">
        <div class="ly__wrapper_head">

            <div class="head__menu">
                <ul class="head__menu_area">
                    <li class="menu__item"><a href="#MissionVision">メニュー1</a></li>
                    <li class="menu__item"><a href="#CEO">メニュー2</a></li>
                    <li class="menu__item"><a href="#JobList">メニュー3</a></li>
                </ul>
            </div>
          

        </div>

    </header>

    <!--メイン画像-->


    <main id="MissionVision">
        <div class="ly__wrapper_head">
            <div class="MissionVision__title_area">

                <h1>xxxxxxxxxxxxxxxxxxxxxxxxxxx</h1>
            </div>


            <div class="MissionVision__guide fadein">

                <h1>xxxxxxxxxxxxxxxx</h1>
                <p class="MissionVision__guide_sentence">
                    xxxxxxxxxxxxxxx
                    </p>
            </div>
            
            <div class="MissionVision__guide _reverse fadein">
                <p class="MissionVision__guide_sub_title">

                </p>
                <h1>xxxxxxxxxxxxxxxx
                </h1>
                <p class="MissionVision__guide_sentence">xxxxxxxxxxxxxxxxxxxxxxxxxxxx</p>
            </div>
        </div>
    </main>

```

```style.css
@charset "UTF-8";
/*ベース
*********************/
body {
  color: #333333;
  font-family: "Noto Sans JP", sans-serif;
}

a {
  text-decoration: none;
  color: #333333;
}

img {
  height: auto;
  max-width: 100%;
}

.break {
  display: block;
}





/*レイアウト
*********************/

/********************/
/*★header
*********************/
.header {
  height: 60px;
}
.header .ly__wrapper_head {
  padding-left: 20px;
  padding-right: 20px;
}

.header .ly__wrapper_head {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}

.head__menu {
  display: none;
}





  .header {
    border:1px solid red;
    height: 100px;
  }
  .head__menu {
    display: block;
  }

  .head__menu {
    margin:0 auto;
    line-height: 100px;
  }

  .head__menu_area {
    display: flex;
    flex-direction: row;
    align-items: center;
  }
  .head__menu_area li:not(:last-of-type) {
    margin-right: 25px;
  }
  .head__menu_area .menu__item a {
    color: red;
    font-family: Noto Sans JP;
    font-size: 12px;
    font-style: normal;
    font-weight: 400;
    line-height: normal;
  }
 

/*追従header*/
.header--sticky {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
  visibility: visible;
  animation: kf-slideDown 0.5s ease-in-out;
  background-color: #ccccff;
  z-index: 20;
}

.header--sticky .menu__item a {
  color: red;
}

@keyframes kf-slideDown {
  0% {
    transform: translateY(-100%);
  }

  100% {
    transform: translateY(0%);
  }
}

#MissionVision {
  margin-top: 191px;
  height: 1243px;
  background-image: url(../img/mission-bg.png);
  background-repeat: no-repeat;
  background-position: bottom center;
}
#MissionVision .MissionVision__title_area {
  text-align: center;
  margin-bottom: 132px;
}
#MissionVision .MissionVision__title_area .MissionVision__sub_title {
  display: inline-block;
  width: 98px;
  height: 12px;
  flex-shrink: 0;
  margin-bottom: 9px;
}
#MissionVision .MissionVision__title_area h1 {
  color: #333;
  font-family: Noto Sans JP;
  font-size: 20px;
  font-style: normal;
  font-weight: 700;
  line-height: normal;
}

```

```script_JQ.js
/*追従ヘッダー */
window.addEventListener('scroll', function() {
	const header = document.querySelector('.header');
	const headerHeight = header.offsetHeight; // ヘッダーの高さを取得
	
	if ($(this).scrollTop() > 100) {
	  header.classList.add('header--sticky');
	  document.body.style.marginTop = headerHeight + 'px'; // コンテンツにヘッダーの高さ分の余白を設定
	} else {
	  header.classList.remove('header--sticky');
	  document.body.style.marginTop = '0'; // コンテンツの余白をリセット
	}
  });

```