CSSだけで写真を繰り返し無限に移動（スライド）するアニメーションの方法がすごいので勝手に解説する

CSSだけで写真を繰り返し無限に移動する方法がないかなとググったら、自分には思いつかない方法で実装している方がいました！

- [写真が画面の端から端へ流れる無限ループするアニメーション &#8211; chocolat](https://chocolat5.com/tips/loop-image-animation/)

感謝ですm(__)m

上記の記事では3つの方法が紹介されています。

元の記事に説明があるのでそれを見ていただければ終わりですが、（僕のように）コードを読んでも理解できない方のために勝手に解説します。

元の記事で紹介されている最初の方法のみを解説します。

ちなみにですが、最終的にこんな感じのアニメーションです。

<p data-height="377" data-theme-id="light" data-slug-hash="oaVgeK" data-default-tab="result" data-user="4cres" data-pen-title="oaVgeK" class="codepen">See the Pen <a href="https://codepen.io/4cres/pen/oaVgeK/">oaVgeK</a> by 4cres (<a href="https://codepen.io/4cres">@4cres</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

コードは下記です。

```html
  <div class="loop_css">
    <img src="img.jpg"><img src="img.jpg">
  </div>
```

```css
.loop_css {
  position: relative;
  display: -webkit-flex;
  display: flex;
  width: 100vw;
  height: 300px;
  left: 50%;
  margin-left: -50vw;
  overflow: hidden;
}

.loop_css img {
  width: auto;
  height: 100%;
}

/* 1つ目の画像 */
.loop_css img:first-child {
  -webkit-animation: loop 50s -25s linear infinite;
  animation: loop 50s -25s linear infinite;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  will-change: transform;
}

/* 2つ目の画像 */
.loop_css img + img {
  -webkit-animation: loop2 50s  linear infinite;
  animation: loop2 50s linear infinite;
}

/*アニメーション*/
@-webkit-keyframes loop {
  0% {
    -webkit-transform: translateX(100%);
    -ms-transform: translateX(100%);
    transform: translateX(100%);
  }
  to {
    -webkit-transform: translateX(-100%);
    -ms-transform: translateX(-100%);
    transform: translateX(-100%);
  }
}

@keyframes loop {
  0% {
    -webkit-transform: translateX(100%);
    -ms-transform: translateX(100%);
    transform: translateX(100%);
  }
  to {
    -webkit-transform: translateX(-100%);
    -ms-transform: translateX(-100%);
    transform: translateX(-100%);
  }
}

@-webkit-keyframes loop2 {
  0% {
    -webkit-transform: translateX(0);
    -ms-transform: translateX(0);
    transform: translateX(0);
  }
  to {
    -webkit-transform: translateX(-200%);
    -ms-transform: translateX(-200%);
    transform: translateX(-200%);
  }
}

@keyframes loop2 {
  0% {
    -webkit-transform: translateX(0);
    -ms-transform: translateX(0);
    transform: translateX(0);
  }
  to {
    -webkit-transform: translateX(-200%);
    -ms-transform: translateX(-200%);
    transform: translateX(-200%);
  }
}
```

一つずつポイントとなるところを解説します。

まず `img` を2つ並べています。親要素の `loop_css` に `display: flex;` を指定しているので横並びになります。

今回表示する画像の横幅は `2500px` とし、最大の想定表示サイズはフルHDサイズ（`1920px`）とします。

![01.png](https://qiita-image-store.s3.amazonaws.com/0/42231/9aa21535-cfe1-dcc8-7d74-c7104aeae808.png)

同じ画像を読み込んでいますが、イラスト上はわかりやすく色分けして `1` `2` と記載します。

左へ移動するアニメーションです。

`2500px` の画像を2つ並べると 想定最大サイズ `1920px` を大きく超えますが、親要素の `loop_css` 　に `overflow: hidden;` を指定しているので親要素を超える部分は表示されません。

ちなみに親要素の `loo_css` に `width: 100vw;` を指定していますが、`vw` はスクロールバーの横幅は考慮されません。

スクロールバーが発生するなら `width: 100%` を指定する方がよいかと思います。

まずは、最初の画像 `1` がどのように動くのか見ていきましょう。

`translateX(0)` は画像を配置した初期値位置なります。

`translateX(100%)` なら右へ自身の横幅分移動した位置になり、`translateX(-100%)` なら左へ自身の横幅分移動した位置になります。

![02.png](https://qiita-image-store.s3.amazonaws.com/0/42231/be7c6c0d-19ef-14f5-2a03-0eec2743a1af.png)

最初の画像は `loop_css img:first-child` で指定しています。

`animation: loop 50s -25s linear infinite;` としているため、`@keyframes loop` のアニメーションが提供されます。

`50s` はアニメーションの開始から終了までの時間で、`-25s` はアニメーションが開始される時間です。

`-25s` なので 25秒早く開始されます。**ここが大きなポイントで、アニメーションが開始される時間で初期位置を調整しています。**

先ほどの図を見ていただくとわかりますが、アニメーション開始時には `translateX(100%)` を指定しているので画面外の右側の位置になりますが、`-25s` を指定することで25秒早い位置、つまり `translateX(0)` の位置から開始されるということです。

![03.png](https://qiita-image-store.s3.amazonaws.com/0/42231/3f2554c8-0ef0-b046-37f0-30a4ad20f85c.png)

`animation` に `infinite` を指定しているので、アニメーションが無限に繰り返されます。

最初だけは `translateX(0)` の位置から開始されますが、ループの2回目以降は `translateX(100%)` の位置から開始されます。

このように指定することで、`1` と `2` の画像を無限にループして表示することができます。

次は画像 `2` の動きを見てみましょう。

![04.png](https://qiita-image-store.s3.amazonaws.com/0/42231/f7acf0a8-ba48-6471-3653-97c1a1a38b44.png)

画像 `2` の動き簡単です。

画像 `2` を配置した初期位置が `translateX(0)` の位置になり、画面外の右になります。

`translateX(0)` から `translateX(-200%)` の位置へ50秒かけて移動します。

このように指定することで画像 `1` と `2` が隙間なく無限にループ表示されます。

仕組みについて理解できたかと思います。

次は応用して右へ移動するアニメーションを作成してみましょう。

# 右へ移動するアニメーションを作成

想定表示サイズ `1920px` と画像サイズ `2500px` は同じで、今度は右へ移動するアニメーションです。

![05.png](https://qiita-image-store.s3.amazonaws.com/0/42231/3fc6b94e-898b-0940-18bc-39e200b45cf3.png)

先ほどのCSSをベースに変更していきます。
先ほどとは逆方向になるので、アニメーションの開始と終了の値を逆にします。

```css
/*アニメーション*/
@-webkit-keyframes loop {
  0% {
    -webkit-transform: translateX(-100%);
    -ms-transform: translateX(-100%);
    transform: translateX(-100%);          /* 先ほどは 100% */
  }
  to {
    -webkit-transform: translateX(100%);
    -ms-transform: translateX(100%);
    transform: translateX(100%);           /* 先ほどは -100% */
  }
}

@keyframes loop {
  0% {
    -webkit-transform: translateX(-100%);
    -ms-transform: translateX(-100%);
    transform: translateX(-100%);          /* 先ほどは -100% */
  }
  to {
    -webkit-transform: translateX(100%);
    -ms-transform: translateX(100%);
    transform: translateX(100%);           /* 先ほどは -100% */
  }
}

@-webkit-keyframes loop2 {
  0% {
    -webkit-transform: translateX(-200%);
    -ms-transform: translateX(-200%);
    transform: translateX(-200%);          /* 先ほどは 0 */
  }
  to {
    -webkit-transform: translateX(0);
    -ms-transform: translateX(0);
    transform: translateX(0);              /* 先ほどは -200% */
  }
}

@keyframes loop2 {
  0% {
    -webkit-transform: translateX(-200%);
    -ms-transform: translateX(-200%);
    transform: translateX(-200%);          /* 先ほどは 0 */
  }
  to {
    -webkit-transform: translateX(0);
    -ms-transform: translateX(0);
    transform: translateX(0);              /* 先ほどは -200% */
  }
}
```

他のCSSは1つ目の画像と2つの目の画像のアニメーションの開始時間の指定のみ変更しています。
1つの目の画像には `-19.2s` を、2つ目の画像には `5.8s` を指定しています。
なぜ、この指定をするのか詳しく見ていきます。

```css
.loop_css {
  position: relative;
  display: -webkit-flex;
  display: flex;
  width: 100vw;
  height: 300px;
  left: 50%;
  margin-left: -50vw;
  overflow: hidden;
}

.loop_css img {
  width: auto;
  height: 100%;
}

/* 1つ目の画像 */
.loop_css img:first-child {
  -webkit-animation: loop 50s -19.2s linear infinite;
  animation: loop 50s -19.2s linear infinite;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  will-change: transform;
}

/* 2つ目の画像 */
.loop_css img + img {
  -webkit-animation: loop2 50s 5.8s linear infinite;
  animation: loop2 50s 5.8s linear infinite;
}
```

今回は右へ移動するアニメーションです。
画像 `1` は `translateX(-100%)` から `translate(100%)` の位置へ50秒かけて移動します。

![06.png](https://qiita-image-store.s3.amazonaws.com/0/42231/72adf526-4307-5ea2-aa25-4df724660941.png)

ご覧の通り、`translateX(-100%)`は画面外の左側の位置ですので、初期位置を画面右端にする必要があります。

![07.png](https://qiita-image-store.s3.amazonaws.com/0/42231/a78b1704-ab3e-4d25-a6db-f399f9c2191a.png)

画面の右端にするには画像を右へ `1920px` 移動する必要があります。
アニメーションは全体で `5000px` を50秒かけて移動します。
`1920px` 移動するのに何秒かかるか計算しましょう。

```
1920 / 5000 * 50 = 19.2秒
```

19.2秒と算出できました。1つ目の画像には `animation: loop 50s -19.2s linear infinite;` と指定することで、画面の右端からアニメーションが開始されます。

次は画像 `2` について見ていきます。
画像 `2` は `translateX(-200%)` から `translate(0)` の位置へ 50　秒かて移動します。

![08.png](https://qiita-image-store.s3.amazonaws.com/0/42231/224aa944-20fe-f0bf-abd5-af07aa36413b.png)

アニメーションの開始位置ですが、`translateX(-200%)` の位置ではなく、画像 `1` の左端の位置にする必要があります。

![09.png](https://qiita-image-store.s3.amazonaws.com/0/42231/b6700c9c-93b5-50f2-ab23-5b9604cee058.png)

`580px` 移動するのに何秒かかるか計算しましょう。

```
580 / 5000 * 50 = 5.8秒
```

2つの目の画像に `animation: loop2 50s 5.8s linear infinite;` と指定することで `画像 `1` の左端からアニメーションを開始することができます。

このように指定することで、右へ移動するアニメーションも可能です。

画像の横幅、想定最大表示サイズによって、指定する秒数が異なりますので、利用する場合は自分で計算して指定してください。

# safari, iOS で CSS アニメーションが動かない（不安定）

僕の環境で上記のアニメーションを作成したときに、mac の Safari と iOS でアニメーションが開始されたり、されなかったりと動作が不安定でした。

jQueryを使って css　を後から読み込むことで解消されました。

- [Qiita - safari, iOS で CSS アニメーションが動かない（不安定）](https://qiita.com/4cres/items/9a6d038d50c504e8e436)

同じような方は試してみてください。

# 1920px以上の表示で左右に白の余白を表示する

想定最大表示サイズが `1920px` なので、それ以上で表示したときにはスライドを中央に表示して左右に余白を表示したいですが、スライドに `margin:0 auto;` の指定ができないので中央に表示できません。
`1920px` 以上で左右に余白を表示したいときは、下記のように白の余白を左右に配置すれば `1920px` で途切れたように表示できます。

```css
@media screen and (min-width : 1920px) {

    .silide1920pxOverSpaceLeft {
        width: calc((100% - 1920px) / 2);
        height: 100%;
        background: #fff;
        position: fixed;
        top: 0;
        left: 0;
        z-index: 9999;
    }
    .slideMenu1920pxOverSpaceRight {
        width: calc((100% - 1920px) / 2);
        height: 100%;
        background: #fff;
        position: fixed;
        top: 0;
        right: 0;
        z-index: 9999;
    }

}
```