davidjerleke / embla-carousel

A lightweight carousel library with fluid motion and great swipe precision.
https://www.embla-carousel.com
MIT License
5.78k stars 174 forks source link

Unexpected results from scrollSnapList method #125

Closed krikienoid closed 3 years ago

krikienoid commented 3 years ago

Hello,

I am trying to create a carousel with this effect, pictured in screenshot 1 below. The implementation is similar to your iOS Picker example, where a rotation angle is calculated from the scroll progress. The problem is when a window resize event is triggered, some of the slides no longer center properly, see screenshot 2. Even if the window is resized by 1px, the difference is pretty drastic.

Screenshot 1

Screen Shot 2020-11-24 at 11 31 46 AM

Screenshot 2

Screen Shot 2020-11-24 at 11 32 00 AM

It seems that when the carousel is first initialized, embla.scrollSnapList() will return [-0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] for a carousel with 10 items, which looks right to me. However, after a resize event, embla.scrollSnapList() will return a different set of values, something like this [-0, 0.15507861048245647, 0.24100075577592645, 0.26451379351226284, 0.31647667722977557, 0.4308486685044219, 0.5452166758190794, 0.5971744258431836, 0.6898427790350868, 0.8449213895175434].

I would like to understand why embla.scrollSnapList() is returning different values after a resize event, and how I can force it to always use the correct snap points generated on initialization.

Thanks in advance

davidjerleke commented 3 years ago

Hi @krikienoid,

Thank you for your question. I'm not 100% sure about this because you didn't provide a CodeSandbox, but this seems quite similar to issue #116.

If my assumption is correct, the issue is caused by the 3D transforms. Upon initialization, Embla reads the dimensions of your slides (width in your case for a horizontal carousel). But transforming elements in 3D space alters the values returned by node.getBoundingClientRect(). And as a result, the embla.scrollSnapList() method will return different values after the resize event.

This is how I solved it in issue #116. Please note that this is a solution for the ReactJS version of Embla. You didn't specify if you're using the VanillaJS or ReactJS version.

I would also like to mention that I updated the iOS Pickers recently because they didn't render correctly in IE11 (issue #104). If you need to support IE11, I suggest that you update your code accordingly.

Let me know if it helps.

Kindly, David

krikienoid commented 3 years ago

Hi @davidcetinkaya, Thank you for the quick reply. I am using the VanillaJS version. Your assumption makes sense to me, I was thinking the same. So really I need to figure out how to get Embla to correctly recalculate those dimensions.

krikienoid commented 3 years ago

Hi @davidcetinkaya, I was able to find a solution. Thank you so much for your help and pointing me in the right direction. Have a nice day!

davidjerleke commented 3 years ago

Glad to hear that @krikienoid. I would like to confirm if the ReactJS solution I mentioned did help you create your solution? Thanks.

Enjoy!

krikienoid commented 3 years ago

@davidcetinkaya, the ReactJS solution to #116 was indeed what I needed. I just needed to figure how to do the same thing with VanillaJS.

Here is the solution I came up with, for anyone who has a similar issue:

embla.on('resize', () => {
    // Remove transforms
    embla.slideNodes().map(slideNode => {
        slideNode.style.opacity = 0;
        slideNode.style.transform = 'none';
    });

    // Re-initialize Embla in order for it to pick up the correct element dimensions
    embla.reInit();
    embla.dangerouslyGetEngine().translate.toggleActive(false);

    rotateSlidesFunc();
});
davidjerleke commented 3 years ago

Thanks @krikienoid.