お世話になっております。コウヤです。
先日、Webデザイン・コーディングの中級卒業課題を終え、プロの方にOKをいただきました!
続けて、PHPやWordpressあたりに手を付けようと思いますが、その前に、今回の課題で得たスキルをまとめていきたいと思います。
今回はページ内を移動した際に、ヘッダーが固定化されるようなデザインを考えていこうと思います。
追従ヘッダーとは
よく見かけるデザイン化と思いますが、ページ内スクロールをすると、以下のようにヘッダーが表示され、それを追従して固定化ように表示させることを考えます。
今回の作成において、スマートフォンによるレスポンシブ化は考慮しておりません。PCのみで考えます。(コードが長くなるため)
ヘッダー部分の作成
まずは追従させることは考慮せず、以下のヘッダー部分の作成をしていきます。(下記の赤枠の箇所)
追従機能を確認するため、HTMLでは「MissionVision」という形で xxxxxxxxxx という文字も入れております。
<!--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>
.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の下にさらに以下のコードを追加します。
#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%の位置に隠れている状態
【最後の100%の時点】
紫背景は0%の位置に表示される状態
これは今回、0%と100%で行ったが、間に50%を入れることも可能ですので試してみてください。
jQueryで動作させる
それではjQueryで動作させます。以下のようにコードを書きます。
/*追従ヘッダー */
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にしています。
##コードまとめ
<!--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>
@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;
}
/*追従ヘッダー */
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'; // コンテンツの余白をリセット
}
});