ちょっと実案件で、「スライドショーを入れて欲しい」という要望があったのですが、矢印で進んだり戻ったり、というような機能が必要なさそうな、単純なスライドショーだったので、CSSだけでやれないかなと思って、作ってみました。
要件(仕様)
- 右から左に流れるタイプ
- 最後まで行ったら1枚目に戻るけど、動きは右から左のママ(=無限ループっぽく)
- 「進む」「戻る」や数を示す●は不要
以上の条件で設計します。
コード
弊社はSass(SCSS)で開発しているので、SassのコードとHTMLの構造を。
Sass
$topSlideShowCount: 4;
$topSlideShowMove: 1s;
$topSlideShowStop: 3s;
$topSlideShowAll: ($topSlideShowMove * $topSlideShowCount) + ($topSlideShowStop * ($topSlideShowCount));
$topSlideShowMoveProportion: $topSlideShowMove / $topSlideShowAll * 100%;
$topSlideShowStopProportion: $topSlideShowStop / $topSlideShowAll * 100%;
.top_slide_show {
overflow: hidden;
ul {
width: ($topSlideShowCount + 1) * 100%;
display: flex;
animation-name: topSlideShow;
animation-delay: 0;
animation-duration: $topSlideShowAll;
animation-iteration-count: infinite;
li {
width: 100% / $topSlideShowCount;
}
}
}
.topSlideShowAll { z-index: $topSlideShowAll;}
.topSlideShowMoveProportion { z-index: $topSlideShowMoveProportion;}
.topSlideShowStopProportion { z-index: $topSlideShowStopProportion;}
@keyframes topSlideShow {
0% {
margin-left: 0;
}
@for $i from 1 through $topSlideShowCount {
#{(($topSlideShowMoveProportion + $topSlideShowStopProportion) * ($i - 1)) + $topSlideShowStopProportion} {
margin-left: #{($i - 1) * -100%};
}
@if ($i < $topSlideShowCount) {
#{(($topSlideShowMoveProportion + $topSlideShowStopProportion) * ($i - 1)) + $topSlideShowMoveProportion + $topSlideShowStopProportion} {
margin-left: #{$i * -100%};
}
} @else {
99.999% {
margin-left: #{$i * -100%};
}
}
}
100% {
margin-left: 0;
}
}
HTML
<div class='top_slide_show'>
<ul>
<li><img src='http://placehold.it/600x400'></li>
<li><img src='http://placehold.it/600x400/ffaaaa'></li>
<li><img src='http://placehold.it/600x400/aaffaa'></li>
<li><img src='http://placehold.it/600x400/aaaaff'></li>
<li><img src='http://placehold.it/600x400'></li>
</ul>
</div>
解説
Sassの変数で数値設定を代入
更新時に枚数やタイミングを変更できるように、枚数と時間を変数で指定。
$topSlideShowCount: 4;
【$topSlideShowCount】で、スライドショーの枚数を指定。
$topSlideShowMove: 1s;
【$topSlideShowMove】で、切り替わりのスピード(時間)を設定。
$topSlideShowStop: 3s;
【$topSlideShowStop】で、止まっている時間を設定。
ダミーの5枚目を入れておく
最後(この例の場合4枚目)になったときも、そのまま右から流れてきつつ、それが1枚目になるようにする必要があるので、HTML側に「1枚目と同じ5枚目」を記述しておきます。
(JSなら動的に1枚目を複製するんですが、今回はJSは使わないので静的に・・・)
width: ($topSlideShowCount + 1) * 100%;
なので、スライドショー自体は4枚ですが、コード上は5枚設置されているので、子要素の「ul」のwidthは【指定枚数+1枚】になるようにします。
overflow hiddenとflexboxを組み合わせて横長に
左右の動きでループするので、横並びに配置する必要があります。
親となる「div要素」に
overflow: hidden;
を指定して、横並びがはみ出しても良いようにして、その子要素となる「ul要素」を
display: flex;
Flexboxにすると、色んな意味で手っ取り早い。
アニメーションキーフレームを使って動かす
枚数とそれぞれの時間を組み合わせて、それらを【@keyframes】で動かします。
【@keyframes】は秒ではなくパーセンテージで、それぞれのタイミングでのプロパティを指定しなければならないので、上記3つの変数を組み合わせた数式を作り、それをSassの関数【@for】でループさせて、タイミングの指定を生成します。
【@keyframes】の流れとしては「停止 → 移動 →停止 → 移動 ・・・」の繰り返しになるようにします。
0% {
margin-left: 0;
}
@for $i from 1 through $topSlideShowCount {
#{(($topSlideShowMoveProportion + $topSlideShowStopProportion) * ($i - 1)) + $topSlideShowStopProportion} {
margin-left: #{($i - 1) * -100%};
}
@if ($i < $topSlideShowCount) {
#{(($topSlideShowMoveProportion + $topSlideShowStopProportion) * ($i - 1)) + $topSlideShowMoveProportion + $topSlideShowStopProportion} {
margin-left: #{$i * -100%};
}
} @else {
99.999% {
margin-left: #{$i * -100%};
}
}
}
100% {
margin-left: 0;
}
最後になったら最初に戻る考え方としては
「最後(例の場合4枚目)になったら、5枚目に移動して指定時間分停止したのち、一瞬で(アニメーションせず)1枚目に戻る。あとのアニメーションはループ」
という感じです。
なので、最後の移動の「次」のアクションを【99.999%】で指定して、動き終わった瞬間に【100%】で1枚目に切り替わるようにしてあります。
これで、擬似的に無限ループになります。
プレビュー
実際の動きは以下。
上記はアニメGIFなんで動き硬いですが、ちゃんとしたものは以下の「CodePen」で確認できます。
CodePen
https://codepen.io/YoshihiroUshio/pen/JjYQYjV
※リセットを効かせるために、ややコード付け加えています。
以上となります。
Javascriptを使っていないので、特にHTML側に無駄なコードが必要になりますが、まぁ単純なスライドショーなら、これくらい平気かな、と。
要件が単純だったのでCSSオンリーにしましたが、ちゃんとしたものを設置するなら、JSプラグインか自分で書くか、したほうが良いですね。
なにかの参考になれば幸いです。
=うしお=