Swiper: Infinite loop with slidesPerView: auto, loopFix() issues

Created on 10 Jan 2019  路  12Comments  路  Source: nolimits4web/swiper

This is a (multiple allowed):

  • [x] bug
  • [ ] enhancement
  • [ ] feature-discussion (RFC)
  • Swiper Version: 4.4.6 (also tested 4.4.x versions and the problem persists)
  • Platform/Target and Browser Versions: all platforms and browsers I've been testing: Windows/Android and Chrome/Opera/Firefox (the most actual versions)
  • Live Link or JSFiddle/Codepen or website with issue:
    -"big case" codepen
    -"small/simplified case" codepen

What I did

I use swiper with the following settings (the "big case"):

autoplay: {
    delay: 0
},
centeredSlides: true,
coverflowEffect: {
    depth: 100,
    modifier: 1,
    rotate: 5,
    stretch: 0
},
effect: 'coverflow',
freeMode: true,
freeModeMomentumBounce: false,
freeModeMomentumRatio: .1,
freeModeMomentumVelocityRatio: .8,
freeModeSticky: true,
grabCursor: true,
loop: true,
loopAdditionalSlides: slidesNum, // slidesNum contains the initial slides number
loopedSlides: slidesNum,
slidesPerView: 'auto',
speed: 20000,
breakpoints: {
    360: {
        slidesPerView: 1
    }
}

+some css styles (I did put them in codepens). After some experiments I've managed to recreate the issue only with these settings (the "small case"):

centeredSlides: true,
loop: true,
loopedSlides: slidesNum,
slidesPerView: 'auto',

I don't know if solving problem for the "small case" will be sufficient for solving the "big case", but for sure it's a good way to start.

Behavior

If I slide to the left, everything seems fine (unless the screen is very big or there are too few slides, i.e. 2), but when I swipe to the right, duplicated elements won't show up on the right side of the slider, which causes a huge empty space after the slides. It's even worse if I swipe very fast (it may cause the whole container to be empty for a moment). Occasionally the slider updates and the duplicates "jump in" to the right place, but it's too soon, so it looks bad and may be confusing for the user.

I could find some similar issues here on GitHub, but none of the presented fixes worked for me. For instance I've been playing with loopedSlides and loopAdditionalSlides options (i.e. I've been trying to put there some huge values like slidesNum, 2 * slidesNum, 10 * slidesNum, 50 or slidesNum - 1, where slidesNum contains the initial slides number). It didn't help.

Moreover I've got impression that changing loopAdditionalSlides value option is doing literally nothing. In the docs it's said that it's the "number of slides that will be cloned after creating of loop", but as far as I could see, number of cloned slides is always equal to the number of original slides - please correct me if I'm wrong. So technically, how does this option work?

The other thing I've tried was translating the slider manually when the very last slide appears on the screen, but then I had problems with smooth movement/free mode momentum (see "Big case").

Attemption to fix this

I've been trying to modify swiper.js script in order to make it work. First of all I've noticed that the method loopFix is responsible for "fixing" the loop (to be more specific it handles the translation of slider if some conditions are met). These conditions look like this:

if (activeIndex < loopedSlides) {
    // Fix For Negative Oversliding
} else if ((params.slidesPerView === 'auto' && activeIndex >= loopedSlides * 2) || (activeIndex >= slides.length - loopedSlides)) {
    // Fix For Positive Oversliding
}

First of all I replaced the 2 multiplier in the second condition with 1 (to tell the truth I couldn't understand why the 2 is there, as activeIndex >= loopedSlides is the opposite condition to the activeIndex < loopedSlides). Can some good soul explain me why there is 2? Thanks!

Secondly I used the console.log and observed that the first condition for negative oversliding was sometimes fulfilled even though I was swiping to the positive direction, so I decided to fix this by imposing some additional condition here related to the sliding direction. So I got something like this:

var previousIndex = swiper.previousIndex;
var dir = (activeIndex > previousIndex) ? 'right' : 'left';

if (dir === 'left' && activeIndex < loopedSlides) {
    // Fix For Negative Oversliding
} else if (dir === 'right' && ((params.slidesPerView === 'auto' && activeIndex >= loopedSlides) || (activeIndex >= slides.length - loopedSlides))) {
    // Fix For Positive Oversliding
}

In general this fix may not be sufficient for some RTL settings, but it helped a little bit in my case. Here is an example: "attemption to fix" codepen.

As you can see it may seem to work now, but there are still some problems:

  • variable dir has got wrong value after first swipe in the opposite direction (for example if we are swiping left and then we swipe right for once, the dir variable still evaluates to 'left' not to 'right'; it'll have the correct value 'right' only if we swipe right for the second time and further). So the problem still may occur in these kinds of situations.
  • fast swiping can still cause swiper container to be partially empty; in the worst scenario I could limit the maximum slider speed, but it's not very user friendly
  • (hard to reproduce) I'm not sure if it concerns the small case, but for the big case in Opera and Chrome browsers some random swiping may cause an infinite script loop (more precisely the method swiper.loopFix(); in line 3038 of the swiper.js (ver. 4.4.6) starts to run infinitely, causing the whole slider to freeze).
bug confirmed contribution welcome has demo has workaround

Most helpful comment

Have the same issue:

const swiperInstance = new Swiper(containerRef.current, {
            direction: 'horizontal',
            slidesPerView: 'auto',
            loopedSlides: 3,
            loop: true
});

With following config Swiper correctly work to the left left, but not to the right.


UPD:

I think the issue reproducible when width of all the slides (not cloned) less than width of "viewport".

All 12 comments

Ok, I think I fixed the major problems in my case (but it may not be sufficient in general).

  1. I modified first condition like this:
    if (dir === 'left' && activeIndex < loopedSlides && !(activeIndex === previousIndex - 1 && previousIndex > loopedSlides / 2)) {

  2. I added an argument "direction" to the loop fix method, which can be "left", "right" or undefined:
    function loopFix (direction) {

  3. I modified the conditions once again, taking the argument into account:

if ((typeof direction === 'undefined' || (typeof direction !== 'undefined' && direction === 'left')) && activeIndex < loopedSlides && !(activeIndex === previousIndex - 1 && previousIndex > loopedSlides / 2)) {
    // Fix For Negative Oversliding
} else if ((typeof direction === 'undefined' || (typeof direction !== 'undefined' && direction === 'right')) && (params.slidesPerView === 'auto' && activeIndex >= loopedSlides) || (activeIndex >= slides.length - loopedSlides)) {
    // Fix For Positive Oversliding
}
  1. I passed an argument to this method in following places:
  • changed swiper.loopFix(); to swiper.loopFix('right'); in slideNext method
  • changed swiper.loopFix(); to swiper.loopFix('left'); in slidePrev method
  • changed swiper.loopFix(); to swiper.loopFix('right'); in the Autoplay variable initialization (but in general the argument here should be dependant on initial slider direction)
  • and the most complicated one; in method onTouchMove I have added var diff = swiper.isHorizontal() ? diffX : diffY; right before the if (!data.isMoved) { condition and then changed the next swiper.loopFix(); to swiper.loopFix(diff > 0 ? 'left' : 'right');

The last point is done like this, because I couldn't get the correct swipe direction in the loopFix method (as stated in the previous post).

Additionally I commented out this fragment:

if (needsLoopFix) {
    swiper.once('transitionEnd', function () {
        swiper.loopFix();
    });
}

as sometimes it was causing the slider to freeze (the loopFix method was called infinitely, I don't know why).

codepen:
https://codepen.io/stasiak/pen/pGvGaq

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Have the same issue:

const swiperInstance = new Swiper(containerRef.current, {
            direction: 'horizontal',
            slidesPerView: 'auto',
            loopedSlides: 3,
            loop: true
});

With following config Swiper correctly work to the left left, but not to the right.


UPD:

I think the issue reproducible when width of all the slides (not cloned) less than width of "viewport".

Yes i also experience this issue.

I would like to add that it has definitely something to do with the combined width of the elements and the viewport.

Also, setting centeredSlides to true, everything works but that's not what i want in my case.

Same issue

There is such a problem. Does anyone know a solution?

@nullorone apparently it's based on the amount of slides you are showing , at least for me that was the case.

I had a slider which initially had 6 swiper-slides per view in my config, but one of those divs didn't exist or was empty because it was being handled programatically, so swiper didn't know what to do with that last one which in turn just messed it up, so in that case I had only two ways to go, to occupy the slides, either use centered slides which made the 5 slides I had , take up the width of 6 slides by centering everything, filling up that last slide without using centered slides or putting slidesperview to 5 which was the amount of swiper-slide divs that were available at the time.

If that helps at all, awesome.

Had the same issue. Fixed mine by duplicating the array of slides with PHP array_merge(), so that there were more slides in total than slides that was showing in the view. Seemed to work for me!

Same here, I duplicated foreach loop in html/php and it works.
It's like manual clone of elements.
It's a bypass, but it's easiest solution for now I think.

Is there an easy workaround for this without duplicating PHP loops or modifying source code?

hmmm. in my case, loopFix event didn't fired on swiper.slideTo()
when i dragged the slides, loopFix is fired well.

Was this page helpful?
0 / 5 - 0 ratings