embla-carousel icon indicating copy to clipboard operation
embla-carousel copied to clipboard

[Bug]: iOS Stutter

Open WilliamWelsh opened this issue 1 year ago • 19 comments

Which variants of Embla Carousel are you using?

  • [ ] embla-carousel (Core)
  • [X] embla-carousel-react
  • [ ] embla-carousel-vue
  • [ ] embla-carousel-svelte
  • [ ] embla-carousel-autoplay
  • [ ] embla-carousel-auto-scroll
  • [ ] embla-carousel-solid
  • [ ] embla-carousel-auto-height
  • [ ] embla-carousel-class-names
  • [ ] embla-carousel-fade
  • [ ] embla-carousel-docs (Documentation)
  • [ ] embla-carousel-docs (Generator)

Steps to reproduce

The bug occurs when I use caoursel.scrollTo(index, false) to smoothly scroll to the selected item.

Expected Behavior

It should scroll smoothly on iOS browsers as it does as non-Safari browsers.

Additional Context

I believe it has something to do with Safari/webkit.

On Android Chrome, it is perfectly smooth. On MacOS Chrome, it is perfectly smooth. On MacOS Safari, it stutters. On iOS Safari, it stutters. On iOS Chrome (which is still WebKit), it stutters.

What browsers are you seeing the problem on?

Safari

Version

8.1.3

CodeSandbox

https://codesandbox.io/p/sandbox/silly-haze-3evud?file=%2Findex.html

Before submitting

  • [X] I've made research efforts and searched the documentation
  • [X] I've searched for existing issues
  • [X] I agree to follow this project's Contributing Guidelines for bug reports

WilliamWelsh avatar May 29 '24 15:05 WilliamWelsh

@WilliamWelsh thanks. While I appreciate the effort, I get issues or questions like this once in a while where the dev in question claims that the scroll animations stutters. It’s really hard for me to do anything about this when I don’t see any stuttering on Safari whether I test it on my iOS or OSX devices. Anything could cause this including a performance heavy implementation of a carousel on top of the Embla library.

Do you have anything else to add, something more substantial that could support your claim and/or help me reproduce this?

davidjerleke avatar May 29 '24 16:05 davidjerleke

If you increase the duration prop, it's easier to notice. Chrome (excluding Chrome iOS) it feels like butter, but every WebKit device/browser I've tried (even on embla-carousel.com) I can notice stutter.

WilliamWelsh avatar May 30 '24 18:05 WilliamWelsh

@WilliamWelsh have you tried well known CSS tricks to promote the container (the element that is scrolled with transform: translate) to a separate layer? Example:

.embla__container {
  backface-visibility: hidden;
}

/* If that doesn’t work, try this instead (not both): */

.embla__container {
  will-change: transform;
}

Does that affect the animation in any way?

davidjerleke avatar May 31 '24 16:05 davidjerleke

It seems to be a lot better with the backface-visibility setting, combined with changing the duration to 10 the animation is so fast that you can't really notice it anymore

WilliamWelsh avatar Jun 03 '24 12:06 WilliamWelsh

It seems to be a lot better with the backface-visibility setting, combined with changing the duration to 10 the animation is so fast that you can't really notice it anymore

@WilliamWelsh so basically no, it didn't help then. I've put together a little test with a simple scroll animation for both JS and CSS here:

If you wouldn't mind, test both of them on webkit and Chrome browsers respectively, and let me know the results. Which ones stutter if any?

Thanks in advance! David

davidjerleke avatar Jun 04 '24 12:06 davidjerleke

Hi @davidjerleke It seems that when using css animation, in low power mode on iphone there is no stutter like with js animation.

sarussss avatar Jun 12 '24 08:06 sarussss

@sarussss when did you check? Right now or a while ago?

davidjerleke avatar Jun 12 '24 09:06 davidjerleke

@davidjerleke I just checked about 30 minutes ago

sarussss avatar Jun 12 '24 09:06 sarussss

@sarussss sorry to ask you but could you try Test once more? Both default and low battery mode and see if there's stuttering going on? I made some changes to the test sandbox like 20 minutes ago.

davidjerleke avatar Jun 12 '24 09:06 davidjerleke

@davidjerleke I just checked it. Default mode: There is no difference between css and js animation. Low battery mode: js animation is still a bit slower than css, but it seems to reduce stuttering.

sarussss avatar Jun 12 '24 10:06 sarussss

@sarussss thanks. What device did you test on?

davidjerleke avatar Jun 12 '24 11:06 davidjerleke

@davidjerleke I use Iphone 15 Pro to test.

sarussss avatar Jun 12 '24 14:06 sarussss

@sarussss thanks! I also tested both on iPhone and MacBook Pro and I couldn’t reproduce any stutter when triggering the JS example, even with low power mode active. However, the JS animation is slightly longer/slower (but still not stuttering). When you say this:

Low battery mode: js animation is still a bit slower than css, but it seems to reduce stuttering.

Do you mean that the JS animation is slower only or also stuttering?

davidjerleke avatar Jun 12 '24 15:06 davidjerleke

@davidjerleke I think is still stuttering, but the stuttering has improved. Video: https://youtube.com/shorts/anKVGukcSNQ?si=hEyE2H7-3Uohlyaz Demo: https://y682vc.csb.app/

sarussss avatar Jun 12 '24 15:06 sarussss

@sarussss thanks for sharing the screen recording. Watching it, I think both stutter (which is expected and makes sense because it’s low battery mode after all), and it seems like the JS animation only stutters slightly more than the CSS animation (the difference is barely noticeable). Do you agree?

davidjerleke avatar Jun 13 '24 11:06 davidjerleke

It's definitely noticeable by a lot of people, which is why I opened the issue

WilliamWelsh avatar Jun 13 '24 12:06 WilliamWelsh

@WilliamWelsh, first off, the Test sandbox has changed since you were here the last time because I've updated it. The JS animation there doesn't use the same animation technique as the current version of Embla Carousel.

Secondly, @sarussss wrote this:

Default mode: There is no difference between css and js animation. Low battery mode: js animation is still a bit slower than css, but it seems to reduce stuttering.

My test results are aligned with what @sarussss wrote above, with the exception that I can barely even notice a difference between the CSS and JS animation when low battery mode is activated. But watching @sarussss screen recording, the CSS animation stutters too. So the difference isn't big by any means.

And the whole point of low power mode is to save battery. Even native apps can stutter. So if the CSS and JS animation is just as smooth in this Test when the battery is loaded, and there's just a slight difference of how much they stutter between the CSS and JS animation in low power mode, I think the approach could be a candidate which could make it to the main library.

@WilliamWelsh I don't understand how this is helping:

It's definitely noticeable by a lot of people, which is why I opened the issue

You didn't answer my following question before:

Do you have anything else to add, something more substantial that could support your claim and/or help me reproduce this?

As I mentioned, Test sandbox has changed since you were here the last time. The stuttering @sarussss mentioned is in low power mode so that doesn't even support your claim about stuttering on webkit browsers. At least not when the battery is loaded.

I'm maintaining this on my spare time so if you don't respect that and you don't have anything constructive to say just don't say anything? What do you mean when you say "a lot of people"? The whole point of this conversation is for me to outline what choices I have moving forward, and the pros and cons of the options I have to solve/improve the animation smoothness. The point is not to read repeating comments that doesn't add any value to this conversation.

davidjerleke avatar Jun 13 '24 13:06 davidjerleke

Hi @davidjerleke Totally agree with you, hope you bring these improvements to Embla, so I can test on Embla when swiping, when swiping it will often be more jerky.

sarussss avatar Jun 13 '24 15:06 sarussss

Thanks @sarussss!

I will definitely see how I can improve the animation engine. Thanks for taking the time to discuss, test and sharing useful information like screen recordings and similar.

davidjerleke avatar Jun 14 '24 07:06 davidjerleke

After investigating this further, I was lucky and found that there was some iOS stutter on very specific carousel sizes and when a carousel had more than 8 slides which is weird. These two things got rid of the iOS stutter for me:

  1. The internal interpolation math for the carousel animation was slightly off. It has been fixed in the following PR: #933. More specifically here in the code. The fix was released in v8.1.7.

  2. This is something devs have to do themselves: Add the following CSS transform: translate3d(0, 0, 0); to all slides. A fix for this was added to the docs in the following commit.

davidjerleke avatar Jul 30 '24 19:07 davidjerleke

Hi @davidjerleke I just checked and the low battery jerking has not improved yet. Video recording doesn't seem to show errors as easily as live viewing. https://github.com/user-attachments/assets/88fd58b4-7b6e-46cf-8bb7-ce5af280b9e6

sarussss avatar Jul 31 '24 01:07 sarussss

@sarussss I’ve also investigated the low battery/battery saving mode and this is my answer:

Embla has a JavaScript spring animation engine that handles the animations instead of simple CSS easings. This means that the animations are done with JavaScript and more specifically with requestAnimationFrame. There are numerous advantages with spring based animations and if you really want to understand the benefits of this design choice, I suggest you check these out:

  • Spring animations talk by Apple developers
  • This article that explains the difference between spring animations and CSS easings.

However, the main downside with JavaScript animations compared to CSS easing transitions is the degraded performance when low battery mode is active. This happens because unfortunately, iOS and some other devices throttle requestAnimationFrame heavily when low battery mode is active. The penalty is actually insane compared to CSS animations. But this is happening on a browser native level. I can’t do anything about it.

With that said, this doesn’t mean that CSS easing transitions should be preferred because of the low battery performance reduction that some browsers apply to JavaScript animations. I think the benefits of spring animations with JavaScript still outweigh simple CSS easings (please at least read the article to understand why). And when I built the Embla core, I didn’t want to build yet another carousel library with CSS easings like almost all other libraries use. They feel stiff like you’re moving around a refrigerator or a huge stone block. I wanted to build a robust spring based carousel library with animations that feel natural, with motion that is proportional to how vigorous the swipe gesture is.

I don’t really understand the design choice of JavaScript animation throttling and the reasons behind it. If the purpose is to save battery, I think it still doesn’t make much sense, because there are multiple ways to destroy the battery without using requestAnimationFrame. Just look at the LinkedIn and Instagram website: Both kill your battery in no time. Especially the LinkedIn website freezes as soon and you interact with it and drains your battery.

On the other hand, one could argue that the battery saving mode is called so because of a reason. Performance restrictions should be expected, both when using a browser and even native apps. But still, I think the level of performance restrictions are way too high. Low battery mode should still allow for a usable experience even if performance is degraded.

So if you or someone else reading this want to try do anything about this, please create a new WebKit bug and share the link so anyone else that sees this can go to the bug report and add a +1 to it to show that it’s frustrating for developers. If we’re lucky, the WebKit team might pick it up and decrease the requestAnimationFrame performance penalty when low battery mode is active.

davidjerleke avatar Jul 31 '24 08:07 davidjerleke

Hi @davidjerleke Thanks for your answer.

sarussss avatar Jul 31 '24 12:07 sarussss

Hey @davidjerleke

First of all sorry for digging up old thread, but I believe it’s the best place for it, given that the issue was not truly resolved. I started to use your carousel and lucky me ofc I have performance issues, even without the low battery mode, still trying to find out why but in the meantime I found this issue and yes - I strongly believe the spring animations are the way to go, yet I don’t relate to your conclusion that we need to use JS - well we don’t:

https://developer.chrome.com/docs/css-ui/css-linear-easing-function

https://github.com/jakearchibald/linear-easing-generator

https://linear-easing-generator.netlify.app/

I am using it with great success in my tailwind-css project for all my other spring animations, and believe me, there is a ton of them. So while I’m working on to find out my issue, I was hoping you could check it out, and maybe even implement it, so maybe, just maybe, my issue would be resolved automatically 😁

Cheers

Forsect avatar Feb 23 '25 22:02 Forsect

@Forsect you will find an answer to your comment here:

  • https://github.com/davidjerleke/embla-carousel/discussions/1141#discussioncomment-12448923

davidjerleke avatar Mar 10 '25 13:03 davidjerleke

@Forsect Just to help narrow things down—what device are you noticing the stutter on?

davidjerleke avatar Apr 24 '25 16:04 davidjerleke

@davidjerleke Sorry, didn't see the message :x Well, all of them. iPhone 16 Pro Max, Samsung Galaxy S23, some other android phones, MBP M3 MAX, all browsers.

Forsect avatar May 15 '25 00:05 Forsect

@Forsect Could you please provide something more concrete that I can work with? A screen recording and a CodeSandbox setup where the issue occurs would be really helpful. Also, does the stutter happen when dragging, or when the animation is triggered by the navigation buttons, or both?

davidjerleke avatar May 22 '25 19:05 davidjerleke

I have problems with iphone 11 ios 16.4 and some other models.

JudithGo avatar Jun 10 '25 16:06 JudithGo

@JudithGo I’d really appreciate it if we could keep things concrete. It’s hard for me to help when claims are made without any supporting detail. If you’re experiencing stuttering and would like me to look into it, please share a CodeSandbox with a reproducible example of your setup so I have something to work with.

Thanks.

davidjerleke avatar Jun 10 '25 16:06 davidjerleke