Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: iOS Stutter #890

Closed
4 of 15 tasks
WilliamWelsh opened this issue May 29, 2024 · 23 comments
Closed
4 of 15 tasks

[Bug]: iOS Stutter #890

WilliamWelsh opened this issue May 29, 2024 · 23 comments
Assignees
Labels
bug Something isn't working resolved This issue is resolved

Comments

@WilliamWelsh
Copy link

Which variants of Embla Carousel are you using?

  • embla-carousel (Core)
  • 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

  • I've made research efforts and searched the documentation
  • I've searched for existing issues
  • I agree to follow this project's Contributing Guidelines for bug reports
@WilliamWelsh WilliamWelsh added the bug Something isn't working label May 29, 2024
@davidjerleke
Copy link
Owner

davidjerleke commented May 29, 2024

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

@WilliamWelsh
Copy link
Author

WilliamWelsh commented May 30, 2024

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.

@davidjerleke
Copy link
Owner

davidjerleke commented May 31, 2024

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

@WilliamWelsh
Copy link
Author

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

@davidjerleke
Copy link
Owner

davidjerleke commented Jun 4, 2024

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

@sarussss
Copy link
Contributor

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

@davidjerleke
Copy link
Owner

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

@sarussss
Copy link
Contributor

@davidjerleke I just checked about 30 minutes ago

@davidjerleke
Copy link
Owner

davidjerleke commented Jun 12, 2024

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

@sarussss
Copy link
Contributor

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

@davidjerleke
Copy link
Owner

@sarussss thanks. What device did you test on?

@sarussss
Copy link
Contributor

@davidjerleke I use Iphone 15 Pro to test.

@davidjerleke
Copy link
Owner

davidjerleke commented Jun 12, 2024

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

@sarussss
Copy link
Contributor

sarussss commented Jun 12, 2024

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

@davidjerleke
Copy link
Owner

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

@WilliamWelsh
Copy link
Author

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

Repository owner deleted a comment from sarussss Jun 13, 2024
@davidjerleke
Copy link
Owner

davidjerleke commented Jun 13, 2024

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

Repository owner deleted a comment from WilliamWelsh Jun 13, 2024
@davidjerleke davidjerleke reopened this Jun 13, 2024
@sarussss
Copy link
Contributor

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.

@davidjerleke
Copy link
Owner

davidjerleke commented Jun 14, 2024

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 davidjerleke added the investigating Issue is being looked into label Jun 21, 2024
Repository owner deleted a comment from ramsunil321 Jul 18, 2024
@davidjerleke davidjerleke removed the investigating Issue is being looked into label Jul 19, 2024
@davidjerleke davidjerleke added the investigating Issue is being looked into label Jul 29, 2024
davidjerleke added a commit that referenced this issue Jul 30, 2024
davidjerleke added a commit that referenced this issue Jul 30, 2024
@davidjerleke
Copy link
Owner

davidjerleke commented Jul 30, 2024

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: [Bug]: Add interpolation to fixed time step to improve animation smoothness #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 davidjerleke added resolved This issue is resolved and removed investigating Issue is being looked into labels Jul 30, 2024
@sarussss
Copy link
Contributor

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

@davidjerleke
Copy link
Owner

davidjerleke commented Jul 31, 2024

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

@sarussss
Copy link
Contributor

Hi @davidjerleke
Thanks for your answer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working resolved This issue is resolved
Projects
None yet
Development

No branches or pull requests

3 participants