模写学習 殴り書き日誌③（Codestep/英会話スクール）

コーディング学習サイト[Codestep](https://code-step.com/)を使用した模写学習での気づきを解説仕様でまとめた記事です。

完全に自分の振り返り用なので悪しからず、、、

# 【HTML/CSS コーディング練習】中級編：ランディングページ／CSSアニメーション

※元サイトは[こちら](https://code-step.com/lp-menu/)

## 学び①：スライドショー

**＜完成見本＞**
スライドショーで画像が切り替わる。
![IMG_0094.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2791726/7e4b453c-741f-f797-f2ae-e6a8defefeca.jpeg)

**＜実装方法＞**
まずは仕組みから整理しておきます。

・スライドショー用の画像３枚を重ねて配置
・画像３枚を透明（非表示）にしておく
・以下を実行するアニメーションを組む
　(1)１枚目の画像の表示
　(2)１枚目の画像を非表示にし、２枚目を表示
　(3)２枚目の画像を非表示３枚目を表示
.
.


**①準備（画像配置）**
　配置方法は以下図の通り。
![IMG_0095.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2791726/0b3940fe-fa42-4d16-ec37-c504d41429c2.jpeg)

```style.css
#mainvisual {
  position: relative;
}

#mainvisual .fade li {
  width: 75%;
  position: absolute;
  top: 0;
  right: 0;
  opacity: 0;
}
```
.
.

**②３枚の画像それぞれにアニメーションの開始時間を設定**
　画像を非表示↔︎再表示するアニメーションを設定することが今回のゴールです。まずは、アニメーションの実行タイミングから設定しておきます。
　[animation-delay](https://developer.mozilla.org/ja/docs/Web/CSS/animation-delay)でアニメーション開始までの待機時間を設定できます。以下は、１枚目は待機時間なし、２枚目は5秒、３枚目は10秒になります。

```style.css
#mainvisual .fade li:nth-child(1) {
  animation-delay: 0s;
}

#mainvisual .fade li:nth-child(2) {
  animation-delay: 5s;
}

#mainvisual .fade li:nth-child(3) {
  animation-delay: 10s;
}
```
.
.

**③アニメーションを設定**
　画像を非表示↔︎再表示するアニメーションを設定します。

<ソースコード>
```style.css
#mainvisual .fade li {
  animation: fade 15s infinite;
  /*fade: animation-name*/
  /*15s: animation-duration*/
  /*infinite: animation-iteration-count*/
}

@keyframes fade {/*fadeの部分はanimation-nameと合わせる*/
/*animation-duration（15秒）を％単位で区切り、各々に処理内容を書く*/
  0% {/*0秒後*/
    opacity: 0;/*処理内容*/
  }
  15% {/*２．25秒後*/
    opacity: 1;
  }
  30% {/*４．5秒後*/
    opacity: 1;
  }
  45% {/*６．75秒後*/
    opacity: 0;
  }
  100% {/*15秒後*/
    opacity: 0;
  }
}
```

まずは[animationプロパティ](https://developer.mozilla.org/ja/docs/Web/CSS/animation)からです。

>animation
>CSS の一括指定プロパティで、スタイルの間のアニメーションを適用します。これは animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode, animation-play-state の一括指定です。

今回は指定している値は以下の３つです。
>animation-name：後の@keyframesで指定したアニメーションルールの名前
>animation-duration：1回のアニメーション周期が完了するまでの所要時間
>animation-iteration-count：アニメーションが停止するまでに再生される回数


次に[@keyframes](https://developer.mozilla.org/ja/docs/Web/CSS/@keyframes)についてです。

>@keyframes
CSS のアットルールで、アニメーションの流れに沿ったキーフレーム（または中間地点）のスタイルを定義することによって、一連の CSS アニメーションの中間ステップを制御します。これにより、アニメーションの中間ステップをトランジションよりも詳細に制御できます。

transitionプロパティでもアニメーション時間などを設定できますが、
例えば何秒後と何秒後にこのアニメーションを実行してほしいというやや難解な命令の場合は@keyframesを使うイメージです。

また、@keyframesはanimationプロパティとセットで使用します。
構文については、animation-durationを％単位で区切り、それぞれのタイミングで実行してほしい処理内容を書く形となります。
.
.

### 動き方を整理する
ここまでで②で３枚の画像に遅延時間を設定し、③でアニメーション時間（15秒）を設定しました。
動き方がどのようになっているかを以下図に整理します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2791726/0e744393-b98a-8f53-cf62-d346916f7159.png)

１枚目がフェードアウトし始めるタイミングで２枚目をフェードインし始める動きをつけていることがわかります。
.
.
## 学び②：要素が見えたタイミングでイベントを発生させるjQueryプラグイン
**＜完成見本＞**
「BBBが選ばれる理由」が見えたタイミングで、「オンライン対応」を左からスライド、「講師はネイティブ」を右からスライドさせて表示させる。
![IMG_0096.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2791726/184312a7-36d8-5d85-64e2-a4b31d15bec2.jpeg)


**＜実装方法＞**
まずはコーディングからです。
```index.html
<div class="bg">
 <div class="slide inview-slide-left">
    <img src="img/icon-pc.png" alt="">
    <p>
      <span class="title">オンライン対応</span>
      <span class="text">24時間いつでも受講できる！</span>
    </p>
 </div>

 <div class="slide inview-slide-right">
    <img src="img/icon-teacher.png" alt="">
    <p>
      <span class="title">講師はネイティブ</span>
      <span class="text">お気に入りの講師が自由に選べる！</span>
    </p>
 </div>
</div>
```

```style.css
/*コードは一部のみ抜粋*/
#reason .slide {
  width: 50%;
  opacity: 0;
}

/*
アニメーション（スライド左）を実行

slide-left：下で定義している「@keyframes slide-left」を実行
0.5s：アニメーションが始まってから終わるまでの時間（0.5sかけて実行）
ease-out：アニメーションの変化（開始時は早く、終了時は緩やかに変化）
0s：アニメーションが始まるまでの時間（0sですぐに実行）
1：アニメーションの繰り返し回数（1回）
forwards：アニメーション終了時の状態をそのまま維持
*/
#reason .slide-left {
  animation: slide-left 0.5s ease-out 0s 1 forwards;
}
/*
アニメーション処理
translateX:親要素（slide）の幅に合わせて移動距離を定義
（親要素のslideのwidthが50%なので、−５０％で要素の半分を左に隠した状態）
100%（0.5秒）かけて要素を表示させながら元の位置（translateX(0)）へ移動させる
*/
@keyframes slide-left {
  0% {
    transform: translateX(-50%);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

/*
アニメーション（スライド右）を実行（※左の処理と同様）
slideはwidth50%なので、translateX(150%)で要素の半分を右に隠した状態
*/
#reason .slide-right {
  animation: slide-right 0.5s ease-out 0s 1 forwards;
}
@keyframes slide-right {
  0% {
    transform: translateX(150%);
  }
  100% {
    opacity: 1;
    transform: translateX(100%);
  }
}
```
translateXの部分だけ理解に時間がかかったので整理します。
横座標の移動距離を指定できるものですが、数値を％指定にすると親要素の幅を基準に移動距離を確定します。

![IMG_0098.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2791726/d1f8ed52-3751-b872-c3a5-2b58a9d3093b.jpeg)

例えば上記のように画面幅が1000pxの場合、slide要素はwidth:50%なので500pxです。
ここでtranslateX(100%)にすると、親要素となるslideが５００pxなので、移動距離は100%×500px=500pxに。150%にすると150%×500pxで７５０pxになります。
この仕組みを活用して要素を移動させます。

最後にJSです。
```main.js
  // BBBが選ばれる理由（スライド左）
  $('.inview-slide-left').on('inview', function(event, isInView, visiblePartX, visiblePartY) {
    if(isInView){
      // 要素が表示されたらslide-leftクラスを追加
      $(this).stop().addClass('slide-left');
    }
  });
  // BBBが選ばれる理由（スライド右）
  $('.inview-slide-right').on('inview', function(event, isInView, visiblePartX, visiblePartY) {
    if(isInView){
      // 要素が表示されたらslide-rightクラスを追加
      $(this).stop().addClass('slide-right');
    }
  });
  // 受講生の声（ふきだし）
  $('.inview-balloon').on('inview', function(event, isInView, visiblePartX, visiblePartY) {
    if(isInView){
      // 要素が表示されたらballoonクラスを追加
      $(this).stop().addClass('balloon');
    }
  });
});
```
jQueryのプラグイン**inview**を使用し、要素が見えたタイミングでイベントを実行させます。
（細かい箇所は[こちらのサイト](https://bashalog.c-brains.jp/13/07/25-095600.php)を参考にしました。）

まずは基本構文からです。
```javascript
$('要素名').on('inview', function() {
  //ブラウザの表示域に表示されたときに実行する処理
});
```

**inviewイベント**は指定要素がブラウザの表示域に表示された際に、呼び出される処理を作ることができる仕掛けを意味します。inviewプラグイン限定のイベントになります。

要はinviewイベントで要素が画面上に見えるかどうかを判定し、
見えた場合は、[コールバック関数](https://qiita.com/nekoneko-wanwan/items/f6979f687246ba089a35)であるfunction関数を実行するワケです。

Jqueryの基本構文のみで実装するとなると、スクロール時に実行するscrollメソッド、コンテンツの位置を取得するoffset().topメソッド、スクロール量を取得するためのscrollTopメソッド、、などが必要になるため、
inviewイベントのみで実装できるのは非常に手間が省けます。

ただ、上記のみだと要素が見えた時の処理しか指定できないので、
一般的には、以下構文を使用します。


```javascript
$('要素名').on('inview', function(event, isInView) {
  if (isInView) {
    //要素が見えたときに実行する処理
  } else {
    //要素が見えなくなったときに実行する処理
  }
});
```
isInviewはイベントを設定する際に受け取ることができる**コールバック関数の引数**のことです。
inviewイベントで要素が画面上に見えるかどうかを判定した結果（true or false）が渡されます。

ちなみにオプションとして使用できるコールバック関数の引数は、他にも以下のようなものがあります。

>visiblePartX
→要素の左側だけが表示域に入ってるとき	'left'
　要素の右側だけが表示域に入ってるとき	'right'
　要素の左右両方が表示域に入ってるとき	'both'
　が渡される

>visiblePartY
→要素の上側だけが表示域に入ってるとき	'top'
　要素の下側だけが表示域に入ってるとき	'bottom'
　要素の上下両方が表示域に入ってるとき	'both'
　が渡される。

なお、eventはコールバック関数の引数を記述する際に必要みたいですが、どのような役割があるのかは調べてもよくわかりませんでした。
本プラグイン配布元にも記述するよう指示があるので、ひとまず必要だということは抑えておきます。

## 学び③: text-alignとalign-itemsの使い分け
**＜完成見本＞**
![IMG_0100.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2791726/7de1ff9a-247b-387d-305c-65a648c74a3d.jpeg)

**＜実装方法＞**
flexコンテナ内のアイテムを配置するプロパティは、**flex-directionの値に合わせて使い分ける**必要があります。

＜ソースコード＞
```style.css
/*ブレークポイントで縦並び＋中央揃えにしている*/
#voice .item-left {
  flex-direction: column-reverse;
  align-items: center;
}

#voice .item-right {
  flex-direction: column;
  align-items: center;
}
```

flex-directionが初期値（row）の場合、横軸側で中央揃えする際はtext-align:center、
縦軸側で中央揃えする際はalign-items:centerと指定しますが、
flex-directionがcolumnに変更された場合、**使用するプロパティは逆転します。**

つまり、横軸側で中央揃えする際はalign-items:centerを、縦軸側で中央揃えする際はtext-align:centerと指定する必要があります。

## 学び④：GIFを使用したアニメーション

**＜完成見本＞**
背景の水玉模様が右上から左下に向かって移動します。
![IMG_0101.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2791726/ccbac884-db31-307e-6744-47e969b6be88.jpeg)

**＜実装方法＞**
GIFファイルを背景に指定するのみでは実装できないため、要素のフェードインなどと同様、
背景要素にanimationを別途指定する必要があります。

**＜ソースコード＞**
```index.html
<section id="summary">
<!--略-->
</section>
```

```style.css
#summary {
/*
fall：下で定義している「@keyframes fall」を実行
10s：アニメーションが始まってから終わるまでの時間（10sかけて実行）
infinite：アニメーションの繰り返し回数(無限に繰り返す)
linear：アニメーションの変化（開始から終了まで一定に変化）
*/
  background: url("../img/bg.gif") repeat;
  animation: fall 10s infinite linear;
}

@keyframes fall {
  0% {
    background-position: 0 0;
  }
  100% { /*左下画面外の座標（x,y)=(-700px, 700px)*/
    background-position: -700px 700px;
  }
}
```