Help us understand the problem. What is going on with this article?

CSSだけで、一方向に無限に流れるスライドショーを作る

More than 1 year has passed since last update.

作りたいもの

こういうやつ。画像が一方向にずっと流れるアニメーション(下はGIF画像なのでカクカクしているけども)。CodePenにも投稿しています(こちら)。これを、JavaScriptやjQueryのプラグインを使わずに。CSSのみで作ります。
1552899979999.gif

*CodePenを開くと画像がすべて読み込まれておらず、ところどころ空欄になってしまっているときがあるかもしれません。その時は、どこかのコードをコメントアウトにし、表示を更新させてから、そのコメントアウトを外して再度表示を更新させると、画像がすべて表示されるようになるかもしれません。

まずは全部のコード

このスライドショーは、作るのに若干テクニックがいるものです。コードを見ただけで仕組みが分かる人のために、まずは全てのコードを載せておきます。

HTML
<div class="container">
  <div class="slider-container">
    <img src="imgA.jpg" class="slider-img">
    <img src="imgB.jpg" class="slider-img">
    <img src="imgC.jpg" class="slider-img">
    <img src="imgD.jpg" class="slider-img">
    <img src="imgE.jpg" class="slider-img">
    <img src="imgA.jpg" class="slider-img">
    <img src="imgB.jpg" class="slider-img">
    <img src="imgC.jpg" class="slider-img">
    <img src="imgD.jpg" class="slider-img">
    <img src="imgE.jpg" class="slider-img">
  </div>
</div>

同じ画像を2回含めていますが、記述ミスではありません。こうする必要があるのです。

CSS
.container {overflow: hidden;}
:root {
  --numOfListA: 5;
  --imgW: 140px;
  --imgH: var(--imgW);
  --mBetweenImg: 50px;
}
.slider-container {
  display: flex;
  font-size: 0;
  animation: slideshow 15s linear infinite;
}
.slider-img {
  width: var(--imgW);
  height:  var(--imgH);
}
.slider-img + .slider-img {margin-left: var(--mBetweenImg);}
@keyframes slideshow {100% {transform: translateX(calc((var(--numOfListA) * var(--imgW) + var(--mBetweenImg) * var(--numOfListA)) * -1));}}

カスタムプロパティを使用していますが、使用しなくても作れます。修正が楽なので使っているだけです。
では仕組みを解説していきます。

仕組み

文章で説明するよりも実際に動いているのを見た方が分かりやすいでしょう。

下のGIFは、画像3枚を無限スライドショーにした際の動きを簡易的に表したものです。本来ならdiv.containeroverflow: hidden;が指定されていますが、それを指定しないとこういう動きになります。
1552913772314.gif
imgA・imgB・imgCはdiv.slider-containerの中のimgタグ(img.slider-img)を表しています。画像と画像の間はvar(--mBetweenImg)ですね。

ここで、div.containeroverflow: hidden;を指定してやると次のようになります。
1552914354142.gif
これを見ていただければ、なぜ同じ画像を含めているのかが分かっていただけるのではないでしょうか。文章で説明するとややこしくなりそうなので、文章での説明は省略させていただきます。

コードの説明

HTML

HTML
<div class="container">
  <div class="slider-container">
    <!-- リストA -->
    <img src="imgA.jpg" class="slider-img">
    <img src="imgB.jpg" class="slider-img">
    <img src="imgC.jpg" class="slider-img">
    <img src="imgD.jpg" class="slider-img">
    <img src="imgE.jpg" class="slider-img">

    <!-- リストB -->
    <img src="imgA.jpg" class="slider-img">
    <img src="imgB.jpg" class="slider-img">
    <img src="imgC.jpg" class="slider-img">
    <img src="imgD.jpg" class="slider-img">
    <img src="imgE.jpg" class="slider-img">
  </div>
</div>

リストAには、スライドショーで流したい画像を入れてください。
リストBには、リストAの画像を上から同じ順番適当な数だけ含めてください。なぜそうする必要があるのかは、言葉で説明するとややこしくなりそうなので、これもGIF画像を置くだけにとどめておきます。

●もし上から同じ順番にしなかったら
1552915568974.gif

●もしリストBのimgタグの数が不十分だったら
1552915660029.gif

CSS

CSS
.container {overflow: hidden;} /* はみ出す部分を見えなくする */
:root {
  --numOfListA: 5; /* リストAのimgタグの数 */
  --imgW: 140px; /* ここで画像の横幅を指定、px指定を推奨 */
  --imgH: var(--imgW); /* ここで画像の縦幅を指定、px指定を推奨 */
  --mBetweenImg: 50px; /* ここで画像間の余白を指定。px指定を推奨 */
}
.slider-container {
  display: flex; /* 画像を横並びにする */
  font-size: 0; /* 余計な余白を削除 */
  animation: slideshow 15s linear infinite;
}
.slider-img {
  width: var(--imgW);
  height:  var(--imgH);
}
.slider-img + .slider-img {margin-left: var(--mBetweenImg);}
@keyframes slideshow {100% {transform: translateX(calc((var(--numOfListA) * var(--imgW) + var(--mBetweenImg) * var(--numOfListA)) * -1));}} /* 下で説明 */

アニメーションでのtranslateXの値について説明します。

アニメーションでは、div.slider-containerを、0%ではこの状態で・・・
155081659966.jpg
100%ではこの状態に持っていきたい。
155081659966.jpg
ということは、移動量は、リストAの画像の枚数(var(--numOfListA))とimg.slider-imgの横幅(var(--imgW))のと、画像間の余白(var(--mBetweenImg))とリストAの画像の枚数(var(--numOfListA))のの分だけ左に移動すればよい。左に移動するということはX軸の負の方向に移動するということだから、-1をかけてやればよい。

応用

例えば、パソコンサイズの画面では画像をもっと大きく表示させたいという場合は、メディアクエリを使えばいいです。例えばこういう風に。

CSS
@media screen and (min-width: 900px) {:root {--imgW: 180px;}}

下の完成形では、実際にメディアクエリを使用して、画面幅によって画像の大きさを変えています。

完成形

こちらのCodePenに載せています。
下のCSSを追記することで、このスライドショーの仕組みが理解しやすくなるかもしれません。

CSS
body {transform: scale(0.5);}
.container {
  overflow: none;
  border: 5px solid black;
}
ryoo_ss
無職系フロントエンドエンジニア。 ランサーズとかココナラとかを通してぜひ依頼してください。 ランサーズ https://www.lancers.jp/profile/ryoo_s_s?ref=header_menu ココナラ https://profile.coconala.com/users/957219
https://ryo.dev/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away