クライアントからのリクエストがあり、イメージを左右に無限ループするギミックを検証してみました。
過去にも実績はあるのですが、今回もう少し入り込んで、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版がいいです。
ただし、自分のスキルとその他のテクニックを全て検証したわではなく、飽くまで個人的な感想です。
今後とも検証したいと思います。