Edited at

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


作りたいもの

こういうやつ。画像が一方向にずっと流れるアニメーション(下は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;
}