
クライアントからのリクエストがあり、イメージを左右に無限ループするギミックを検証してみました。
過去にも実績はあるのですが、今回もう少し入り込んで、jquery版とcss版でどちらが最適か考察してみました。
今回の要件
- 複数のイメージが右から左にループスライド
- イメージにhoverアクション実装
- イメージにゆっくり揺れるアニメーションを実装
チェックポイント
以下のチェックポイントを基準に検証してみました。
- 実装しやすいか
- 拡張しやすいか
- レスポンシブルへの対応
cssでループを実装してみる
まずはCSSのみで実装してみました。以下のようなイメージになります。

では、cssをみてみます。
css
.loop_bnr {
position: relative;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row nowrap;
flex-flow: row nowrap;
width: 100vw;
overflow: hidden;
}
.loop_bnr ul {
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row nowrap;
flex-flow: row nowrap;
width: 100%;
margin: 0;
padding: 0;
position: relative;
}
.loop_bnr li {
display: inline-block;
width: calc(100vw / 2);
margin: 0px 20px;
list-style: none;
text-align: center;
position: relative;
cursor: pointer;
top:20px;
height:400px;
}
.loop_bnr li:nth-child(2n){
top:80px;
}
.loop_bnr li:nth-of-type(5),
.loop_bnr li:nth-of-type(6),
.loop_bnr li:nth-of-type(7),
.loop_bnr li:nth-of-type(8){
display:none;
}
.loop_bnr .inner_box{
position:absolute;
top:0;
left:0;
width:300px;
height:300px;
}
.loop_bnr img {
max-width: 100%;
height: auto;
border-radius:20px;
filter: grayscale(0);
transition-duration: 0.5s;
}
.loopslide_text {
width:100%;
height:100%;
position: absolute;
top: 0%;
left: 0%;
transition-duration: 0.5s;
opacity:0;
}
.loopslide_text_body {
padding:0px;
}
.loopslide_text_body>h4 {
font-size: 20px;
color: #ffffff;
}
.loopslide_text_body>p {
font-size: 16px;
color: #ffffff;
padding:10px;
}
.loop_bnr li:hover .loopslide_text{
opacity:1;
border-radius:20px;
background: rgba(0, 0, 0, 0.5);
}
.loop_bnr li:hover img{
filter: grayscale(100%);
transition-duration: 0.5s;
}
.loop_bnr ul {
-webkit-animation: loop 50s -25s linear infinite;
animation: loop 50s -25s linear infinite;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
will-change: transform;
}
.loop_bnr ul + ul {
-webkit-animation: loop2 50s linear infinite;
animation: loop2 50s linear infinite;
}
.loop_bnr:hover ul {
animation-play-state: paused;
}
.loop_bnr li.yureru{
transform-origin: center bottom;
animation: yurayura1 10s linear infinite;
}
@keyframes yurayura1 {
0% , 100%{
transform: rotate(2deg);
}
50%{
transform: rotate(-2deg);
}
}
.loop_bnr li:nth-child(2n).yureru{
transform-origin: center bottom;
animation: yurayura2 10s linear infinite;
}
@keyframes yurayura2 {
0% , 100%{
transform: rotate(-2deg);
}
50%{
transform: rotate(2deg);
}
}
display: flex;とflex-flow: row nowrapで横並びにします。イメージのマージンはwidth: calc(100vw / 2)でコントロールします。.loop_bnr liをhoverすることで隠れていたテキストが表示され、イメージがモノクロになります。
ループアニメーションは以下で設定しています。
.loop_bnr ul {
-webkit-animation: loop 50s -25s linear infinite;
animation: loop 50s -25s linear infinite;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
will-change: transform;
}
.loop_bnr ul + ul {
-webkit-animation: loop2 50s linear infinite;
animation: loop2 50s linear infinite;
}
.loop_bnr ul + ulてとこなんか変ですよね….
これはHTMLでわかるのですが、.loop_bnr内にulが2ブロックあり、イメージ名1〜4までを記述し、その後に5〜8までを記述します。
つまり最初のulに遅れて次のulがスライドしてくるというタイムラグアニメーションです。
.loop_bnr:hover ul {
animation-play-state: paused;
}
上記では、ulエリアをhoverした際アニメーションが止まります。
揺れるアニメーションはjquery版と同じで.yureruに設定しています。
html
<div class="loop_bnr"> <ul> <li class="yureru"> <div class="inner_box"> <img src="img/slide1.jpg" alt=""> <div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.1</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </li> <li class="yureru"> <div class="inner_box"> <img src="img/slide2.jpg" alt=""><div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.2</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </li> <li class="yureru"> <div class="inner_box"> <img src="img/slide3.jpg" alt=""><div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.3</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </li> <li class="yureru"> <div class="inner_box"> <img src="img/slide4.jpg" alt=""><div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.4</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </li> 中略 <li class="yureru"> <div class="inner_box"> <img src="img/slide8.jpg" alt=""><div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.8</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </li> </ul> <ul> <li class="yureru"> <div class="inner_box"> <img src="img/slide5.jpg" alt=""><div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.5</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </li> <li class="yureru"> <div class="inner_box"> <img src="img/slide6.jpg" alt=""><div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.6</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </li> <li class="yureru"> <div class="inner_box"> <img src="img/slide7.jpg" alt=""><div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.7</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </li> <li class="yureru"> <div class="inner_box"> <img src="img/slide8.jpg" alt=""><div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.8</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </li> </ul> </div>
先に書いた通り、2つのulで動いています。
とここで以下のCSSの説明になります。
.loop_bnr li:nth-of-type(5),
.loop_bnr li:nth-of-type(6),
.loop_bnr li:nth-of-type(7),
.loop_bnr li:nth-of-type(8){
display:none;
}
わざわざこう書いたのはレスポンシブ対応のためです。正直、そのままでは崩れます。
検証してみたのですが、モバイルでループ処理自体が難しく、最適化させる早道はPCとモバイルではソースを分けることでした。(まあ未熟なのですが…)
そのため@media screenではdisplay:blockにし、.loop_bnr ul + ulはnoneにしました。加えて、display: flexではなくblockにし.loop_bnr liをfloatにしてループそのものをやめました。
まあモバイルでループというのもどうかな?て感じですが、最適化に多少手こずる結果になりました。
もう一つ。
ulが2つある状況がプログラムで生成する場合は、ちょっと不細工かなと..
ただ、数量とサイズのレギュレーションが明確で、固定ブロックとして利用するのであればjsがない分軽量であるとは思います。
また、アニメーションが止まる仕様のため、リンク要素があればいいと思いました。
jqueryでループを実装してみる
続いてjquery版をみてみます。

jqueryを設定する
<script src='https://code.jquery.com/jquery-3.3.1.min.js'></script>
css
.wrapper {
overflow: hidden;
width: 100%;
}
.slider {
display: flex;
}
.slider__inner {
width: 100%;
margin:100px 0;
display: flex;
}
.reverse {
display: flex;
/*overflow: hidden;*/
width: 100%;
margin:100px 0;
}
.reverse__inner {
display: flex;
}
.slider__inner:first-child {
animation: loop 90s linear infinite;
}
.slider__inner:nth-child(2) {
animation: loop2 90s -60s linear infinite;
}
.slider__inner:last-child {
animation: loop3 90s -30s linear infinite;
}
@keyframes loop {
0% {
transform: translateX(200%);
}
to {
transform: translateX(-100%);
}
}
@keyframes loop2 {
0% {
transform: translateX(100%);
}
to {
transform: translateX(-200%);
}
}
@keyframes loop3 {
0% {
transform: translateX(0%);
}
to {
transform: translateX(-300%);
}
}
.reverse__inner:first-child {
animation: loop4 90s linear infinite;
}
.reverse__inner:nth-child(2) {
animation: loop5 90s -60s linear infinite;
}
.reverse__inner:last-child {
animation: loop6 90s -30s linear infinite;
}
@keyframes loop4 {
0% {
transform: translateX(-100%);
}
to {
transform: translateX(200%);
}
}
@keyframes loop5 {
0% {
transform: translateX(-200%);
}
to {
transform: translateX(100%);
}
}
@keyframes loop6 {
0% {
transform: translateX(-300%);
}
to {
transform: translateX(0%);
}
}
.slider__item{
position: relative;
}
.slider__item:nth-child(2n){
top:20px;
}
.loopslide_inner {
position: relative;
cursor: pointer;
margin:0 10px;
}
.loopslide_inner>img {
max-width: 100%;
height: auto;
filter: grayscale(0);
transition-duration: 0.5s;
border-radius:20px;
}
.loopslide_text {
width:100%;
height:98%;
position: absolute;
top: 0%;
left: 0%;
transition-duration: 0.5s;
opacity:0;
}
.loopslide_text_body {
padding:10px;
}
.loopslide_text_body>h4 {
font-size: 16px;
color: #ffffff;
}
.loopslide_text_body>p {
font-size: 14px;
color: #ffffff;
}
.loopslide_inner:hover .loopslide_text{
opacity:1;
background: rgba(0, 0, 0, 0.5);
border-radius:20px;
}
.loopslide_inner:hover img{
filter: grayscale(100%);
transition-duration: 0.5s;
}
.yureru{
transform-origin: center bottom;
animation: yurayura1 10s linear infinite;
}
@keyframes yurayura1 {
0% , 100%{
transform: rotate(2deg);
}
50%{
transform: rotate(-2deg);
}
}
.yureru:nth-child(2n){
transform-origin: center bottom;
animation: yurayura2 10s linear infinite;
}
@keyframes yurayura2 {
0% , 100%{
transform: rotate(-2deg);
}
50%{
transform: rotate(2deg);
}
}
css版と同様にflexで横並びにします。
.slider__innerで右から左に、.reverse__innerは左から右にイメージがループします。
また、css版と同様にタイムラグアニメーションを以下で設定しています。
.slider__inner:first-child {
animation: loop 90s linear infinite;
}
.slider__inner:nth-child(2) {
animation: loop2 90s -60s linear infinite;
}
.slider__inner:last-child {
animation: loop3 90s -30s linear infinite;
}
@keyframes loop {
0% {
transform: translateX(200%);
}
to {
transform: translateX(-100%);
}
}
@keyframes loop2 {
0% {
transform: translateX(100%);
}
to {
transform: translateX(-200%);
}
}
@keyframes loop3 {
0% {
transform: translateX(0%);
}
to {
transform: translateX(-300%);
}
}
その他の設定は大体CSS版と同様ですが、ulが2ブロックあるような設定はありません。
html
<div class="slider"> <div class="slider__inner"> <div class="slider__item yureru"> <div class="loopslide_inner"> <img src="img/slide1.jpg" alt="" width="300"> <div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.1</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </div> 中略 <div class="slider__item yureru"> <div class="loopslide_inner"> <img src="img/slide7.jpg" alt="" width="300"> <div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.7</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </div> <div class="slider__item yureru"> <div class="loopslide_inner"> <img src="img/slide8.jpg" alt="" width="300"> <div class="loopslide_text"> <div class="loopslide_text_body"> <h4>No.8</h4><p data-truncation="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </div> </div> </div> </div> </div>
上記は.slider__innerのみのソースです。見てわかる通り、1ブロック内に全てのイメージが挿入されます。プログラムの生成には向いてると言えます。
javascript
jQuery(function($){
$('.slider__inner').each(function(){
var sliderWidth = $(this).width();
$(this).clone(true).insertBefore(this);
$(this).clone(true).insertAfter(this);
$('.slider').css('width', sliderWidth*5);
});
$('.reverse__inner').each(function(){
var sliderWidth = $(this).width();
$(this).clone(true).insertBefore(this);
$(this).clone(true).insertAfter(this);
$('.reverse').css('width', sliderWidth*2);
});
});
対象セレクタを以下で設定します。
$('.slider__inner').each(function(){
イメージの数に応じて表示サイズのコントロールは以下で設定します。
$('.slider').css('width', sliderWidth*5);
ここちょっと面倒ですが、数が増えた場合そのままの数値(*5部分)だとイメージサイズが相対的に小さくなります。このあたりが、プログラムとの親和性に少し面倒ですね。
また、このままではhoverでアニメーションが止まりません。
レスポンシブについては良いです!そのままのサイズで問題なければmadiaクエリを使用する必要はありません。
css版とjquery版のまとめ
| 実装しやすいか | 拡張性があるか | レスポンシブルへの対応 | |
| css版 | ▲ | ✖️ | ✖️ |
| jquery版 | ● | ▲ | ● |
ということで、個人的にはjquery版がいいです。
ただし、自分のスキルとその他のテクニックを全て検証したわではなく、飽くまで個人的な感想です。
今後とも検証したいと思います。