18

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/

Jennifer Goncalves
  • 1,349
  • 10
  • 24
MAXIM
  • 4,662
  • 15
  • 78
  • 125
  • 1
    The [Flickity](https://flickity.metafizzy.co/) 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](https://jsfiddle.net/ConnorsFan/vm9nn5e0/5/). – ConnorsFan Aug 02 '17 at 04:33
  • Looks good that, I'll give it a try! – MAXIM Aug 02 '17 at 09:42

7 Answers7

22

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>
ConnorsFan
  • 58,595
  • 11
  • 85
  • 120
7

@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.

Shyam Shingadiya
  • 3,227
  • 1
  • 19
  • 36
  • 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. – Patrick Roberts Aug 04 '17 at 14:12
  • @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. – Shyam Shingadiya Aug 04 '17 at 15:46
3

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).

Maciej Kwas
  • 5,417
  • 2
  • 24
  • 43
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);
rudenich
  • 21
  • 1
  • 1
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"] {

}
Artur Bajak
  • 29
  • 1
  • 5
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/

0

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;  
}