Slick: Miscalculated width of slides track on variableWidth with progressive lazy load

Created on 15 Nov 2014  路  92Comments  路  Source: kenwheeler/slick

Hi Ken,
First of all - great plugin, fantastic work, respect!

However, with the new feature "variableWidth" combined with progressive lazy load and centerMode, I encountered problems when having higher amount of image slides in the slick (ca 100+).

The width of "slick-track" element on first few calls to setDimensions seems to be miscalculated - track is slightly shorter than it should be, as the images while initializing do not give correct slide width to the slick.

The effect of this issue is fairly bad: slide-track expands for two rows (as the fully loaded images can not fit within miscalculated track width).

After while (when all progressive images are fully initialized), all is getting back OK, f.e. after first slide change all gets finally calculated correctly and slick is looking fine.

I did not have a time to dive deeper in your code, so i just created kind a dirty hack to fix it (see bellow), but I think this issue shall be addressed and get resolved more elegant way.

The merit of my hack is simple:

1) it simply checks the slick-track width on every call to setDimensions, and compares previously calculated width with the newly calculated. if it differs (width changes as the lazy loading images still continue initializing), it sets the track width manually for INSANE value, e.g. 500000 (to surely accommodate all slides).

2) Once slick-track width stabilizes (previously calculated width equals to new), all returns to normal and manually setting the insane width is bypassed. Track has correct width, and looks good.

As the process is quite quick, the hack does not have any bad influence on initial display, the slick simply starts "fixed" as it would normally, but it is really dirty hack. ;-)

THE HACK

First, I created new var for storing the slick-track width (at line ca 144):
_.lastTrackWidth = 0;

Than, I modified the setDimensions method, inside >variableWidth === true< condition (line ca 1335):

    } else if (_.options.variableWidth === true) {
        var trackWidth = 0;

        // *** edit
        // *** HACK for miscalculated track width while progressive lazyLoad (wrong slide widths)
        if (_.options.lazyLoad == "progressive" && _.$slideTrack.width() !== _.lastTrackWidth ) {
            trackWidth = 500000;
        }
        // *** END edit

        _.slideWidth = Math.ceil(_.listWidth / _.options.slidesToShow);
        _.$slideTrack.children('.slick-slide').each(function(idx){
            trackWidth += Math.ceil($(this).outerWidth(true));
        });
        _.$slideTrack.width(Math.ceil(trackWidth) + 1);

        // *** edit
        // *** HACK for miscalculated track width while progressive lazyLoad (wrong slide widths)
        _.lastTrackWidth = Math.ceil(trackWidth) + 1;
        // *** END edit

    } else {

Please, I am sure you will have better idea, and I hope in a mean time the above may help somebody to resolve this issue in a dirty way, before fixed in source.

Thanks

Confirmed

Most helpful comment

I was having this same issue. My fix was similar to @alvinpascoe. One of the parent elements was set to display:table. Once I changed this parent to display:block, the issue was solved.

All 92 comments

I am experiencing the same issue in variableWidth, centerMode with slick-track not calculating the correct width on page load. This leads to multiple rows of slides as @NinjaBCN described. I see this issue even without lazy loading, and only about ten 100kb images. I think the cause in both of our cases is that slick-track width is being set before all images are loaded, and then not updated until the next interaction.

After while (when all progressive images are fully initialized), all is getting back OK, f.e. after first slide change all gets finally calculated correctly and slick is looking fine.

Agreed, after images are done loading the issue is corrected on the next update (slickNext, slickPrev, window resize, etc.) Obviously all images are available at this point so slick has no problem calculating slick-track width.

The effect of this issue is fairly bad: slide-track expands for two rows (as the fully loaded images can not fit within miscalculated track width).

For me, the slides stack in a single column straight down the page, but same issue (slick-track is not wide enough.) My fix was CSS-only, setting an initial slick-track width to a large value and then letting slick override it when done loading images.

I was not able to recreate the issue in jsFiddle, so I suspect that the combination of larger images and other assets in my production environment cause enough of a delay for this issue to appear.

I'm also having the same issue: variable width, center mode causing slides to appear in multiple rows, but resolves upon update.

Example gallery here: http://www.celebrationsltd.com.php53-4.ord1-1.websitetestlink.com/gallery/sunset-surprise/, click into any of the "more galleries..." menu below it on the page and you will be able to see more examples.

Well then, this will be a priority item. Expect a fix before the end of the weekend.

Awesome. Looking forward.

@kenwheeler You're awesome. This was the issue I failed miserably in describing on reddit last week. I wasn't sure if it was a bug because I couldn't recreate in jsFiddle, although I continue to see it in production: http://staging.celebrateditaly.com/properties/hotel-stendhal/ (I put some CSS in place to limit slick's height and hide subsequent rows of slides, which is why you may only see one centered slide instead of multiple rows).

Also worth noting is that I do not see the issue appear on _every_ page load. Sometimes slick displays normally on initial load, and then subsequent refreshes will cause the issue to appear.

I also only see it in WebKit-based browsers鈥擲afari and Chrome (both Mac OS X and Windows 8). Firefox and IE 10+ display correctly after initially shuffling the images around.

The image shuffling is visible in all browsers before finally settling down and centering the first slide. I'm not sure if there's anything we can do about that since slick can't predict the future and won't know the total width until all images are loaded. Again, in stripped down test cases it's not an issue, but in combination with larger images and other assets vying for bandwidth, it appears.

Not by a computer, but I'm thinking I can fire setPosition/Dimensions each time an image loads.

I'm not sure whether to add this as a separate issue or if it's the same one, but I have a hunch it's the latter so adding it here, apologies if I'm mistaken.

I am also seeing this in Webkit browsers only (Safari on initial load only, Chrome on about 70% of page loads), also in variable width mode only, but not just in center mode and without lazyload on. However, rather than multiple rows of slides resulting, I'm getting just one very thin slide, always 17px in width, over to the left of the slider:
Correct loading / Broken loading

Is this the same bug? Hoping very much that it is since it looks like you're already working on it and it's a bit of a showstopper - very very grateful you're taking a look at it!

@kevinwhoffman Do you know what version you're using? I can't get the same code to reproduce it here: http://jsfiddle.net/thekenwheeler/rewg6bcz/2/ , but it happens every single time on your staging server

@emmawinston anywhere I can see that in the wild?

@kenwheeler Sure, http://davisla.com/newsite/expertise/ and http://davisla.com/newsite/workstages/ . Most consistently broken in Chrome, and I can't replicate it at all in Firefox.

Edited to add - not sure if this is relevant, but it's a WordPress installation pulling the images in from the database via custom fields. I have no idea if this would lead it to behave differently from static content.

Are you guys all using Wordpress? Is slick loaded by hand or via a plugin?

@kenwheeler Slick itself is loaded by hand for me, but the images it grabs are pulled into each post/page via the Advanced Custom Fields plugin.

@kenwheeler Interesting, I'm also using WordPress and loading images from Advanced Custom Fields gallery. I'm using WordPress' version of jQuery if that makes a difference... so I have to type out jQuery instead of $. Not sure if that would affect slick.

I was including slick.js in a minified JS file. I just removed it and replaced it with the CDN link so hopefully that's easier for you to debug. I also uncompressed my CSS so you can see additional styles added to the slider beginning with the .kwh-hotel-slider class.

Example: http://staging.celebrateditaly.com/properties/castello-del-nero/

Edit: @TPDBrendan is also using WordPress.

For what it's worth, I'm not using Wordpress's jQuery - I'm using 1.11.1, Google-hosted, which isn't set to noconflict mode.

I have likewise turned my caching plugin off so everything should be unminified if that's at all useful.

(A quirk of my installation though - I ended up having to embed Slick's CSS styles into my main CSS file, couldn't get them working otherwise for some reason. I suspect that's not relevant but it's the most edge-case thing about my installation I think.)

While we're getting everything out on the table, the most mind-boggling thing is that I can't recreate the issue locally. The exact same site using a local version of WordPress (MAMP) does not show the issue that appears remotely on a GoDaddy shared hosting site. That's the part that makes me think load time is an issue. When all assets are local, they load super fast before slick-track width is set, but remotely they take longer. That's all I got.

Conversely, I am seeing it on an identical MAMP local installation. However, after the first load (which is always broken) _sometimes_ subsequent loads are OK on Chrome and they are nearly always OK on Safari.

I have noticed slower load times tend to correlate with the issue.

Because I can't reproduce this locally, its very difficult to debug. Can you guys try something for me? on the window load event:

$(window).on('load', function(){
    $('.your-slider')[0].slick.setPosition()
});

Hello,

so for my case - i am not using wordpress or any other cms, the slick is loaded clean and pure as from your source.

The only CSS-fix as noted by @kevinwhoffman did not work for me, as i wrote, the first time the slick is overriding the CSS with calculated width, it is wrong so i had to stick with js hack.

One thing it may help is, that if you log a width of each element while in loop of calculating the track width (in setDimensions), you will see the widths are changing for few first calls to setDimensions, and than stabilizes on the correct one.

Bellow i attach a dump of such logs, left is first call, right is the third call (first with stabilized (correct widths. The second call has the widths in between, so for illustration i will just include the first and last one.

I hope it helps.

screen shot 2014-11-16 at 14 13 16

Is that third call the proper values, and when is that called?

yes, the third has the proper values, and it is called on the first slide change -> that means, there was a time to finish init of the images.

just to note, i am using responsive settings, thats why it is a third call i guess (1st on init, 2nd on responsive refresh, third on first slide change), if i understood your code correctly.

Can you confirm that setPosition is called on window.load

just typing it in, in a moment

while using the on load setDimensions, it seems not helping. the logged widths are still changing by each call until it stabilizes, so the display effect is the same.

but shouldn't all of the images be loaded by onLoad?

eh, i guess not, as it is progressive lazy load - the images itself does not have the src tag at the time, just data-lazy attrib. when slick initializes, then the atribs get switched. Maybe i understood you wrong, you want to init the slick completely on window.load instead document.ready? (sorry, just woke up, still a bit foggy world to me) ;-)

Can you stick a setPosition in the progressiveLazyLoad method?

will do. to be clear, you mean fire the set position at the progressiveLazyLoad, right?

If you could, fire inside the method at the end, and try after the method is called in the init method

still the same. if i log the individual widths while calcul, once you give it a bit time, calcul is correct. but when slick is displayed, it gets 2 (or more rows, depends on the amount of slides). after first slide change it sets fine. To quote on @kevinwhoffmans, when i artificially downgrade the load speed (bandwidth), issue is even worst. when full bandwidth, it is "better", as it appears randomly, and not that often.

Ok. I'm starting to warm up to the absurdly large track idea.

Out of curiosity, are any of you guys hiding the parent/slider at any point during load?

oh ya, could not it be related to cloning of the slides (infinite)? just an idea, as sometimes by the numbers it seems that track width would be just fine if there are no slides cloned, one they are added, it breaks the dimensions.

i thought to fire the setDimensions/setPositions after each image physically loads (as you suggested), but to me it would need also a check if that specific image was loaded in full and ONLY AFTER THAT really ADD IT to the track with dimensions adjusted. Than IT HAVE TO WORK, as we deal with real dimensions, and not trying to insert image to the track while still in loading.

Ando to your pref question: nope, i do hide the slider.

and nope, i do not hide the slider.

Does it still happen when infinite is set to false

yes.

besides the "add image once fully loaded", i have another strange idea:

i am using alt tag with images. when images is added to the track, before they are loaded, they have only the data-lazy attribute -> therefore the alt tag is displayed within the image element and defines its width in layout. can this cause some problems?

i mean the alt attribute, clearly.

@kenwheeler So I just added

jQuery(window).on('load', function(){
    jQuery('.kwh-hotel-slider')[0].slick.setPosition();
    console.log('setting position');
});

...and it seems to have worked?! There is still some unsightly jumping, but the multiple rows issue is gone. I see a single squished slide centered, then the full row jumps, then it settles in correctly: http://staging.celebrateditaly.com/properties/castello-del-nero/

Except that on certain pages (not all), the second slide appears empty until first interaction. I wasn't seeing this until adding your window.on() script.

empty-slide

Example: http://staging.celebrateditaly.com/properties/hotel-metropole/

Do you think this variableWidth, centeredMode issue is separate from the lazy load issue? I don't want to hijack @NinjaBCN's thread if that's the case.

What shows when you inspect the second element?

I think all of this is related, particularly to variableWidth

Ok so upon inspection, it looks like the the slides are stacking in multiple rows. I have a static height in my CSS to hide that stuff, but it's definitely there. So again the issue is slick-track is not wide enough. It starts at 2111px and then jumps to 5421px (the correct width) after the first button click.

Seen in Chrome 38.0.2125.122 on Mac OS X 10.7.5.

@kenwheeler I'm hiding the whole page with a loader until document.ready. I get a flash of unstyled images stacked vertically before the slider loads otherwise. I am trying to find a way to prevent this so I can ditch the loading graphic. I'm not lazy-loading the images themselves.

Since the issue resolves on the first interaction after images load, is there some sort of hot fix we can put in place to trigger that refresh as soon as images finish loading?

Try putting a setPosition on line 1161, where each progressively loaded image loads.

@kenwheeler I didn't have any luck using setPosition because I kept getting JS errors (I didn't know the exact syntax to do what you recommended). But I did make a small discovery...

I found that explicitly setting the width attribute on each image seems to stop the stacking issue. I created a foreach loop that loops through an array of images and grabs the image width for every slide. It then plugs that value into the HTML width attribute. This allows me to still use the variableWidth setting because the width is calculated on a per-image basis.

The code below WordPress specific, but the main takeaway is the HTML width attribute:

<?php
    // Get array of images from Advanced Custom Fields image gallery
    $images = get_field('miscellaneous_images');
?>
<?php if( $images ): ?>
    <div class="kwh-hotel-slider">
        <?php foreach( $images as $image ): ?>
            <?php
                // Explicitly set HTML width attribute using values stored in gallery array
                // Syntax here is specific to Advanced Custom Fields gallery field
                $image_width = $image['sizes']['hotel_slider-width'];
            ?>
            <div class="kwh-hotel-slider__slide">
                <img width="<?php echo $image_width ?>" data-lazy="<?php echo $image['sizes']['hotel_slider']; ?>" alt="<?php echo $image['alt']; ?>" />
            </div>
        <?php endforeach; ?>
    </div>
<?php endif; ?>

Here's the JS I used to initialize slick:

jQuery('.kwh-hotel-slider').slick({
    infinite: true,
    speed: 500,
    centerMode: true,
    variableWidth: true,
    autoplay: true,
    autoplaySpeed: 4000,
});

Here it is in the wild: http://staging.celebrateditaly.com/properties/empire-palace-hotel/

Tested in WebKit-based browsers on Mac and Windows. I don't see anymore stacking.

Oh wow. You have access to that from the get go?

In my specific example, I am using an array generated by the Advanced Custom Fields plugin's gallery field.

It's a plugin, not native to WordPress, but I believe there is a native WordPress function to do something similar. I think the wp_get_attachment_img_src() function would do the trick since it also returns width/height attributes.

In Webkit, having this issue using settings: variableWidth, with/without centermode, and with lazyload set to progressive OR ondemand: http://www.beaconnected.com/ng_site/?page_id=11 (also... using slick 1.3.13 manually installed in WP 4, grabbing images via wp_query, and jquery 1.11)

@pilgrimish Since you are using WordPress, can you try implementing the solution I described in https://github.com/kenwheeler/slick/issues/790#issuecomment-63580544? By setting the HTML width attribute, I was able to fix the issue.

Try using wp_get_attachment_image_src to get the dimensions of the images you are including in the slider. Use the width that the function returns to set the HTML width attribute.

I cannot seem to get my variable width carousel to have a max height of 200px no matter how hard I try. Is this bug related to my issue?

http://jsfiddle.net/bnbq7nq4/2/

Here is a Fiddle reproducing my issue AND the exact bug everyone else is describing in above comments. e.g. Resize the browser window when the fiddle loads to initialize the layout of Slick Carousel.

Thanks for this plugin Ken!

Nevermind. This resolved my issue. However the original issue described in this ticket still persists. Just thought my issues may have been related.

.slick-slide {
   height:200px;
}

.slick-slide img {
   height:200px;
}

@kenwheeler.. Sorry to be a bother here, but I'm concerned my issue is different than the issue this ticket discusses. Can you confirm my Fiddle above is reproducing this issue? If so perhaps this is a good example of the issue.

Yup, on Christmas break now, I'll review it when I get back.

Cool cool.. thnx.

I was able to work around this issue by adding a min-width of 100% to the .slick-track. If you need to get this to work and are unsure of how to accomplish it with js, I would give that shot.

Thanks @chrisdatlas, this didn't work for me though. Here's demonstration of what I see. Any help here would be great. I'm kinda going bonkers as demo day get's closer and closer. :) http://jsfiddle.net/bnbq7nq4/6/

Hey @that1guy, sorry you didn't have any luck with the min-width. For whatever reason that seems to have resolved the incorrect sizing of the .slick-track on my site. I'll try to take a look this weekend to see if I can come up with another workaround.

Thanks @chrisdatlas, adding the min-width of 100% to .slick-track worked for me; now they aren't stacking small images anymore

Hi @kenwheeler, noticed this is slated for 1.4 bug fix. Any estimation of when this milestone might be hit. Thanks very much!

@That1guy starting this weekend

@kenwheeler nice! :+1:

Fixed on dev

Hi @kenwheeler.. Please do call me a dummy if I'm being one, but I don't see dev branch. :) Where can I grab this fix from?

I'm in the process of finishing up the docs and releasing 1.4. We're talking like 20 minutes here.

oop! Sorry man! All good.

@kenwheeler Just writing to say thank you. This resolved my issue. you rock!

If i make VariableWidth true the last slide slides down to form a new row just by one pixel but if i inspect it and increase the width of .slideTrack class it sets to one row and works perfectly.

Can you help me with this issue @kenwheeler

@krishna9960 can i see a jsFiddle of your settings.

Hey guys, im having this exact same problem and im using 1.4.1.

$('#hotel-details-modal .gallery').slick({
    dots: true,
    infinite: true,
    speed: 500,
    slidesToShow: 1,
    centerMode: true,
    variableWidth: true
  });

Images stack vertically at page load but if i make any interactions with the carousel it gets fixed, weird, any ideas?

@vjnunez is your slider hidden at first?

Hi

Im having the same problem. And also using 1.4.1

With my basic knowledge I've tried to replicate it here:
https://jsfiddle.net/ArtmanPT/evg9ymxp/42/
(i've used the same number of images and proportions - w/h ratio - as my project)

Only appears when the window size is below +/-1000 px.

In my project the slider is not hidden.
...and adding the min-width of 100% to .slick-track didn't worked for me.

I hope this can help you.

@kenwheeler greta components man
But am facing a problem on the phone with the following settings
$('.slickCarousel').slick({
lazyLoad: 'ondemand',
dots: true,
infinite: false,
speed: 300,
slidesToShow: 1,
centerMode: true,
variableWidth: true ,
adaptiveHeight: true,
autoplay: true
});
All the images have been cropped with the same height 500px but it have a lagging in the movements when it comes to phone screen and screw the order of the pictures are showing and sometimes it repeat the first image. I have tried different settings but all have the same problem on the phone that the movement is not correct. Would appreciate your response.

I'm having the same issue using the latest jquery-slick-rails gem . At certain breakpoints the images start stacking in rows like Emma's (16th Nov) except you can see the whole image on both (or some times all 3) rows. My settings are:

$('.cat_caro').slick({
dots: false,
infinite: true,
speed: 300,
slidesToShow: 1,
centerMode: true,
variableWidth: true
});

.slick-track width is too narrow and gets calculated fresh each time the image slides. If I manually widen .slick-track in developer tools then the issue resolves itself.

Having this issue as well with v1.4.1, same thing as @rorykoehler : .slick-track seems to be one slide too narrow. If I add a slide width to the amount in the inspector, things are working peachy.

Slider Settings:

$('.event-slider-slides').slick({
    dots: true,
    appendDots: '#event-slider-controller',
    draggable: false,
    variableWidth: true,
    adaptiveHeight: false,
    infinite: false
});

@iamhexcoder upgrade to the latest version 1.5.0.1 https://github.com/bodrovis/jquery-slick-rails

It seems to have rectified all my issues :)

@rorykoehler I'm using the non-rails version, pulled from the official github repo via composer - but maybe I will try to sift through this rails version

1.51 will be released soon

@kenwheeler Thanks for an awesome carousel.

Just to let you know the issue still occurs if the image is ridiculously wide (ie much wider than 100% width of the screen). It's not a huge problem as images generally won't be that wide but it would be nice for it to work from a mobile touch perspective. In my use case the carousel still bumps the images down when photographer uploading the files uploads an image that consists of 3 related images grouped together side by side into one image file (panorama style). I wouldn't say it's a priority issue as it works fine with more normal width images and I think I have a work around for this in any case (though still have to try it out).

Having an issue similar that's similar, but the dimensions of the sliders are coming out absolutely huge in only in IE8 and only in the production environment.

slick-slider classes are getting widths of 3500+ pixels and growing each time the slider slides.

It works in an isolated test case and on our mockups, so I can't isolate what's causing this, except possibly the speed at which the images are loading.

Wondering if anybody has an idea of what could be causing this or how to work around it

Having that same issue seen on smaller screens like so:
image

Just wondering what the best way to deal with this would be?
we're using:
$(this).slick(
$.extend({
arrows: true,
infinite: true,
lazyLoad: 'ondemand',
dots: true,
slide: '.slide-item',
slidesToShow: window.defaultSlidesToShow,
slidesToScroll: window.defaultSlidesToShow,
responsive: [
{
breakpoint: 1280,
settings: {
slidesToShow: window.desktopSlidesToShow,
slidesToScroll: window.desktopSlidesToShow
}
},
{
breakpoint: 820,
settings: {
slidesToShow: window.tabletSlidesToShow,
slidesToScroll: window.tabletSlidesToShow
}
},
{
breakpoint: 580,
settings: {
slidesToShow: window.mobileSlidesToShow,
slidesToScroll: window.mobileSlidesToShow
}
}
]
}, $(this).data('slick')));
});

I'm experiencing a slightly different behaviour in 1.5.0, Firefox 37.0.1, only in Firefox, only in variable width sliders.
Should load like this:
screen shot 2015-05-08 at 17 42 44

Instead loads like this:
screen shot 2015-05-08 at 17 39 41

But not always, very inconsistently.

Looking at the slick-track it's getting very large widths, over 5000 pixels, as thedamon describes above. Any help appreciated!

I also found I was having issues with the carousel expanding to extremely large widths (and breaking page layout).

At first I came up with a fix to force a carousel container width (based on the $(window) width) but then I found the real source of my problem.

The issue was being caused by a clearfix on a parent container (it wasn't the immediate parent, but about 4 or 5 levels up).

After removing the clearfix, the carousel behaved as expected!

This is why I love open source projects, I find a bug, I come to raise a bug, I find a patch solution, I update and everything works. Much thanks @kenwheeler - Great project!

I was having this same issue. My fix was similar to @alvinpascoe. One of the parent elements was set to display:table. Once I changed this parent to display:block, the issue was solved.

Thanks @larzilla that was my issue too!

Hello Ken,

I am getting the same issue, but I am using vertical carousel. It initially calculate wrong height. How can I fix this. Also I would like to start a child slider on that slide which has slick-current class. How can I achieve this. Please help me on this.

Thanks

Is there any solution to the slick-track not being wide enough hence multiple rows of tracks? If anybody has hot fix then please let me know.

Thank you,

not sure if this is an issue anymore, but I thought I'd share what I did.

on line 500 or so, I changed

if ($(window).width() < _.breakpoints[

to

if (window.innerWidth < _.breakpoints[

and in my app's code, used

window.innderWidth as well

Thanks @ahnbizcad I will give a shot.

In case someone is still facing this issue, check out this question:
https://stackoverflow.com/questions/43216603/slick-initial-width-calculation-incorrect

screenshot 2
i'm using slick slider on tab. it's works well but, only on 1st tab. it's mean slick-track class width will be 0 for 2nd and 3rd tabs.

how can i solve this plz help me

The below piece of CSS worked for me.

.slick-initialized .slick-slide {
    padding: 0;
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

REPTILEHAUS picture REPTILEHAUS  路  3Comments

NozX18 picture NozX18  路  3Comments

xtatanx picture xtatanx  路  3Comments

Libig picture Libig  路  3Comments

crstauf picture crstauf  路  3Comments