slick slider - css transition infinite loop bug
Asked Answered
C

12

22

I've got a slider set up using slick slider. When using the next and previous buttons, the item comes in to view with a nice transition. The problem I'm having is that when it restarts its cycle, the first item "snaps" into view, instead of doing the transition. Furthermore it seems like it loses it's internal indexing, as the css "odd" and "even" classes are changed. See snippet below:

$(document).ready(function() {
    $('.items').slick({
        slidesToShow: 2,
        speed: 500
    });
});
* {
  margin: 0;
  padding: 0;
}

ul {
  list-style: none;
  height: 150px;
}

.slick-list, .slick-track {
  height: 100%;
}

ul li {
  width: 350px;
  height: 100%;
}

ul li .content {
  width: 100%;
  height: 100%;
  transition: transform 0.5s linear;
  text-align: center;
}

ul li .content span {
  color: #fff;
  font-size: 50px;
  font-family: Arial;
  position: relative;
  top: 50%;
  transform: translateY(-50%);
  display: block;
}

ul li:nth-child(odd) .content {
  background-color: red;
}

ul li:nth-child(even) .content {
  background-color: green;
}

ul li:not(.slick-current) .content {
  transform: scale(0.9);
}
<link href="https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js"></script>
<ul class="items">
  <li class="item">
    <div class="content">
      <span>1</span>
    </div>
  </li>

  <li class="item">
    <div class="content">
      <span>2</span>
    </div>
  </li>

  <li class="item">
    <div class="content">
      <span>3</span>
    </div>
  </li>

  <li class="item">
    <div class="content">
      <span>4</span>
    </div>
  </li>

  <li class="item">
    <div class="content">
      <span>5</span>
    </div>
  </li>
</ul>

I think I know why it's doing this, it's because it has to create "cloned" items for the infinite loop functionality to work. I've tried a few different slider plugins and they all seem to have similar issues.

Does anyone know how I can fix this? jsfiddle here: https://jsfiddle.net/7kdmwkd9/1/

Chatter answered 30/7, 2017 at 23:43 Comment(2)
The Flickity slider does not seem to have the "snapping" problem. As for the odd/even styling problem, you could do this: if you have an odd number of items, duplicate the list. See this jsfiddle.Gerson
Looks good that, I'll give it a try!Chatter
G
26

Solution 1 - Use Flickity

If you want to try another carousel control, you can have a look at Flickity. According to my tests with the wrapAround option, it does not "snap" the first item back into position when the full cycle is complete; the transition goes on smoothly. You can see it at work in this jsfiddle.

As for the problem with formatting the items according to their even/odd index, it happens only when you have an odd number of items. One solution would be to duplicate the list of items. Intead of

Item 1 / Item 2 / Item 3 / Item 4 / Item 5

you could define

Item 1 / Item 2 / Item 3 / Item 4 / Item 5 / Item 1 / Item 2 / Item 3 / Item 4 / Item 5

That would ensure that you work with an even number of items.


Solution 2 - Slick Slider: add transition delay

With Slick Slider, adding a delay to the transition helps to make it smoother when the cycle completes. In the code snippet below, I replaced:

ul li .content {
  transition: transform 0.5s linear;
  ...
}

ul li:not(.slick-current) .content {
  transform: scale(0.9);
}

with

ul li .content {
  transition: transform 0.3s linear;
  transition-delay: 0.5s;
  ...
}

ul li:not(.slick-current) .content {
  transform: scale(0.9);
  transition-delay: 0s;
}

$(document).ready(function() {
  $('.items').slick({
    infinite: true,
    speed: 500,
    slidesToShow: 2,
    variableWidth: false
  });
});
* {
  margin: 0;
  padding: 0;
}

ul {
  list-style: none;
  height: 150px;
}

.slick-list,
.slick-track {
  height: 100%;
}

ul li {
  width: 350px;
  height: 100%;
}

ul li .content {
  width: 100%;
  height: 100%;
  transition: transform 0.3s linear;
  transition-delay: 0.5s;
  text-align: center;
}

ul li .content span {
  color: #fff;
  font-size: 50px;
  font-family: Arial;
  position: relative;
  top: 50%;
  transform: translateY(-50%);
  display: block;
}

ul li:nth-child(odd) .content {
  background-color: red;
}

ul li:nth-child(even) .content {
  background-color: green;
}

ul li:not(.slick-current) .content {
  transform: scale(0.9);
  transition-delay: 0s;
}
<link href="https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js"></script>
<ul class="items">
  <li class="item">
    <div class="content">
      <span>1</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>2</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>3</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>4</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>5</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>1</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>2</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>3</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>4</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>5</span>
    </div>
  </li>
</ul>
Gerson answered 2/8, 2017 at 14:28 Comment(6)
I modified my answer to give a solution for slick slider.Gerson
I used your solution for Flickity slider and that is what I have gone with. Thanks :)Chatter
Great solution, Just adding transition-delay fixed the issue. Good to learn this. Vote upBrickey
2022 and this problem still occurs, thank you. Adding the transition, and inverting the design by targeting ALL the items and giving them the design we want on the current-active one and resetting the style for the items that are not the current-active one worked perfectly !Donella
@Donella would you please share an example?Continuo
Thanks, this fixed a CLS issue for meDandruff
B
6

@GSTAR, Eventually there is no error in your code but there is bit css and js flow you need to understand while using slick.

Slick is cloning your slides and amend in top and down of your slide. like describe below.

Your Code before Slick implementation

<ul class="items">
    <li class="item"><div class="content"><span>1</span></div></li>
    <li class="item"><div class="content"><span>2</span></div></li>
    <li class="item"><div class="content"><span>3</span></div></li>
    <li class="item"><div class="content"><span>4</span></div></li>
    <li class="item"><div class="content"><span>5</span></div></li>
    <li class="item"><div class="content"><span>6</span></div></li>
</ul>

Your Code After Slick implementation

<ul class="items">
    <li class="item slick-cloned"><div class="content"><span>4</span></div></li>
    <li class="item slick-cloned"><div class="content"><span>5</span></div></li>
    <li class="item slick-cloned"><div class="content"><span>6</span></div></li>

    <li class="item"><div class="content"><span>1</span></div></li>
    <li class="item"><div class="content"><span>2</span></div></li>
    <li class="item"><div class="content"><span>3</span></div></li>
    <li class="item"><div class="content"><span>4</span></div></li>
    <li class="item"><div class="content"><span>5</span></div></li>
    <li class="item"><div class="content"><span>6</span></div></li>

    <li class="item slick-cloned"><div class="content"><span>1</span></div></li>
    <li class="item slick-cloned"><div class="content"><span>2</span></div></li>
    <li class="item slick-cloned"><div class="content"><span>3</span></div></li>
</ul>

Also after adding this your animation code is working fine. but it can not visually visible. if you increase this animation time than it will not snaps your browser.

If you replace javascript code than you will come to know what is happening.

<script type="text/javascript">
    $(document).ready(function() {
        $('.items').slick({
            centerMode:true,
            slidesToShow: 3,
            speed: 500,
            infinite: true,
            cssEase: 'linear',
            variableWidth: true
        });
    });
</script>

So after loop get finished and reaching to the first slide animation executed and before reach it get finished.

Please check below my snippet.

$(document).ready(function() {
    $('.items').slick({
        slidesToShow: 2,
        speed: 500
    });
});
* {
  margin: 0;
  padding: 0;
}

ul {
  list-style: none;
  height: 150px;
}

.slick-list, .slick-track {
  height: 100%;
}

ul li {
  width: 350px;
  height: 100%;
}

ul li .content {
  width: 100%;
  height: 100%;
  transition: transform 0.5s linear;
  transition-delay: 0.5s;
  text-align: center;
}

ul li .content span {
  color: #fff;
  font-size: 50px;
  font-family: Arial;
  position: relative;
  top: 50%;
  transform: translateY(-50%);
  display: block;
}

ul li:nth-child(odd) .content {
  background-color: red;
}

ul li:nth-child(even) .content {
  background-color: green;
}

ul li:not(.slick-current) .content {
  transform: scale(0.9);
}
<link href="https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js"></script>
<ul class="items">
  <li class="item">
    <div class="content">
      <span>1</span>
    </div>
  </li>

  <li class="item">
    <div class="content">
      <span>2</span>
    </div>
  </li>

  <li class="item">
    <div class="content">
      <span>3</span>
    </div>
  </li>

  <li class="item">
    <div class="content">
      <span>4</span>
    </div>
  </li>

  <li class="item">
    <div class="content">
      <span>5</span>
    </div>
  </li>
  <li class="item">
    <div class="content">
      <span>6</span>
    </div>
  </li>
</ul>

In infinite loop you have user odd and even css so as per the loop it your next first slide(cloned slide) has green color but your original slide(first slide) has red color hence it flicking color also. If you use number of slides in %2, then this will not happen.

enter image description here

Hope it will help you to understand better.

Brickey answered 4/8, 2017 at 6:42 Comment(2)
This solves the styling issue (in an admittedly clever way), however, the first slide still snaps into place, while you seem to claim you have solved it.Trinitrobenzene
@Patrick : Again read my answer, I mentioned that what's happening,I try to explain why it snaps. I never claimed that I solved it, I just gave another way to handle it.Brickey
S
4

This is not an issue, it's a feature - this is just how slick slider (and most of other infinite-loop sliders) works. Basically, if slider would only clone divs it would end up with a huge performance issue, thus in certain places (beginning/end) after animation it rerender whole thing to start over.

If you are interested here is a proof-of-concept of slider that is based on transition and does not clone anything, just changes positions. Also maybe there is possibility to achieve the same with order - haven't tried but thought about it now.

https://codepen.io/prowseed/pen/QMEQxg - of course it requires a lot of work to make it fully usable, but I tried to make it responsive and the most similar to your example. You just have to keep track of index to add/remove certain classes (.current for example).

Stria answered 2/8, 2017 at 2:3 Comment(0)
N
2

Here my hack for slick.js Warning!! use its carefully, cause its alter source code of plugin

1) Find function
Slick.prototype.setSlideClasses and replace its definition from

 Slick.prototype.setSlideClasses = function(index) 

to

Slick.prototype.setSlideClasses = function(index, oldSlide)

2) in body of this function after code

_.$slides
    .eq(index)
    .addClass('slick-current');

add

if(oldSlide!=undefined){
    if(index==0 && oldSlide!=1){
        var _current = this.$slides.eq(this.$slides.size()-1);
        var __index = allSlides.index(_current);
        var ss = allSlides.eq(__index+1);
        ss.addClass('slick-current');
    }
    if(index==this.$slides.size()-1 && oldSlide!=this.$slides.size()-2){
        var _current = this.$slides.eq(0);
        var __index = allSlides.index(_current);
        var ss = allSlides.eq(__index-1);
        ss.addClass('slick-current');
    }
}

3) find function Slick.prototype.slideHandler in its body replace call

oldSlide = _.currentSlide;
_.currentSlide = animSlide;
_.setSlideClasses(_.currentSlide);

to

oldSlide = _.currentSlide;
_.currentSlide = animSlide;
_.setSlideClasses(_.currentSlide,oldSlide);
Novation answered 12/6, 2018 at 8:19 Comment(2)
Would be awesome if this fixed it. Alas, it does not.Adventuresome
This works for going to next slide, but the glitch remains when going to prev slides. Can you patch this fix? Would be awesome to have both directions working!Spar
T
1

Infinity set to true, CenterMode set to false add effect to current just css

/* slide when not active*/ 
.slick-slide[aria-hidden="true"]:not(.slick-cloned) ~ .slick-cloned[aria-hidden="true"] {

}

/* slide when active (when play last to first) */ 
.slick-slide[aria-hidden="true"]:not([tabindex="-1"]) + .slick-cloned[aria-hidden="true"]  {

}
/* slide when active (when play first to last) */ 
.slick-slide[aria-hidden="true"] + .slick-cloned[aria-hidden="true"] {

}
Talent answered 3/4, 2020 at 15:34 Comment(0)
P
0

@Maciej Kwas

It might be a feature but on this site when you look on slider with "Center Mode" it works fine, the animation looks OK when sliding from last to first slide. http://kenwheeler.github.io/slick/

Pozzuoli answered 4/8, 2017 at 11:16 Comment(0)
B
0

Since I have trouble letting go of the past, I'm still using Slick. I came across this issue and it turned out the problem was my slider images were using srcset attributes. Remove that fixed the issue.

Bellay answered 15/12, 2021 at 14:3 Comment(0)
S
0

Applying transition on ".slick-center" class instead of ".slick-active" solved this issue for me

.slick-slide {
  transform: scale(0.85);
  pointer-events: none;
  transition: transform 0.6s linear;
}

.slick-center {
  transform: scale(1);
  pointer-events: all;
Spell answered 3/5, 2023 at 20:13 Comment(0)
G
0

try to add animation within slick-center class and not slick-current

Gauldin answered 16/8, 2023 at 9:49 Comment(2)
attach example so that get proper confirmation.Imprison
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Cockloft
L
0

Building on previous answers, I found that if you add a transition delay to the .slick-current equal to (or higher) than the slider's slide animation speed, it all works out perfectly. Note that I also added a transition delay of 0s to all other slides.

So with a speed setting of 500ms and without inverting the transforms :

ul li .content {
  transform: scale(0.9);
  transition: transform 0.3s linear;
  transition-delay: 0s;
}

ul li.slick-current .content {
  transform: scale(1);
  transition-delay: 0.5s;
}
Lawrenson answered 5/10, 2023 at 7:30 Comment(0)
S
0

I found that it only happened for me if I started by going to the next slide, going to the previous slide and then forward didn't had the issue it, so for me adding an .on('init') fixed it

const slider = $('#{{$unique_id2}}').on('init', function(e, s){
    s.slickPrev();            
    s.slickNext();        
}).slick({
    lazyLoad: 'progressive',
    infinite: true,
    arrows: true,
    ...
Spline answered 17/4 at 10:3 Comment(0)
D
-1

I found a really simple solution to my version of the issue, which was that once all 4 slides had completed it would loop back round aggressively / buggy.

I found that adding the following provided an infinite loop with no glitching

.slick-track {
transition: fade 2000ms ease-out;  
infinite: true;  
}
Dennard answered 18/2, 2021 at 10:10 Comment(4)
Infinite? Really men?Shockley
@BabkenAsryan Yep, worked perfectly for me.Dennard
Is there such feature?Shockley
This worked accessing the .slick-track class that I found inspecting the Slick Slider being used, which I why I think it was accepted.Dennard

© 2022 - 2024 — McMap. All rights reserved.