Blank Carousel when looping with 2 slides (inactive browser tab)
See original GitHub issueHello,
when trying to create an automated slideshow with two slides and loop: true
, I stumbled upon an interesting edge case. I used setInterval()
to call scrollNext()
every few seconds. After I switched tabs and came back later (one or two minutes is enough), the embla carousel was blank and the source code had a weird transform value:
<div class="embla__container" style="transform: translate3d(-5.72608e+10%, 0px, 0px);">
It can be reproduced here: https://codesandbox.io/s/embla-carousel-align-start-vllyp
I think this only happens in quite specific conditions - e.g. I was only able to reproduce this with two slides. I worked around the problem by using the Page Visibility API and only calling scrollNext()
if the page is visible, but I thought it might be worth reporting the issue.
Issue Analytics
- State:
- Created 4 years ago
- Comments:9 (5 by maintainers)
Hello Gerhard (@niubsta),
I’ve done some digging and I know why this is happening. My initial hunch was kinda right, the
setInterval()
timer is clashing withrequestAnimationFrame()
.Why this is happening at all
Basically, what’s happening is that as soon as the browser tab is blurred, Embla stops doing visual updates because
requestAnimationFrame()
is designed to not run on an inactive browser tab. This makes sense because it saves processing power and battery by preventing expensive rendering from taking place when a tab is blurred. BUT, as you can see in the screenshot below,setInterval()
is running even though the tab is inactive and callingscrollNext()
repeatedly.Embla resets the
targetVector
inside the visual render loop, and it must happen here in order to create the seamless infinite effect. But as already mentioned, the render loop is paused when the browser tab is blurred which means that nothing is stoppingtargetVector
from growing out of hand whenscrollNext()
is called bysetInterval()
.Why this is happening with 2 slides only
Embla uses a specific approach to cover an edge case when the carousel only has 2 slides. When it has more than 2 slides, both
scrollPrev()
andscrollNext()
will find thetargetVector
(to which position the carousel should scroll) by looking for the shortest route possible.scrollNext()
will in this case always move forward because the shortest route from i.e. slide index 0 to 1 is forward. This is because a backward movement to index 1 would have to scroll by all slides from the last index down to 1, causing this route to be longer. BUT, when the carousel only has 2 slides, the shortest route from slide index 0 to 1 could actually be backward, even thoughscrollNext()
is called!This can be confusing because
scrollNext()
is expected to always move forward, andscrollPrev()
backward. This is why Embla only adds to thetargetVector
when it has 2 slides. In contrast, when it has more than 2 slides, it will compare all possible routes and choose the smallest possibletargetVector
which preventstargetVector
from growing out of hand.Conclusion
I hope I’ve managed to explain why this happens 😅. I’m gonna argue that this isn’t a bug. Maybe we should ask the question: Why should we run autoplay for a carousel when the browser tab is blurred? But the main reason is that at the time of writing autoplay isn’t a native feature of Embla Carousel and I’m going to leave the implementation up to the user. There’s a couple of ways to avoid the issue you describe. Below are two different ways:
I hope that this makes sense? Anyways, I’m very happy for your contributions and clear demonstrations! Thank you very much for reporting this and don’t hesitate to do it again. I’ve added you as a contributor 🎉.
Best, David
Hello @davidcetinkaya ,
first of all - kudos for the extraordinarily detailed explanation! 😃
I was a bit confused when you explained that when using
scrollNext()
with two slides the animation actually goes backwards. This isn’t the case in the example code in my initial post. The animation always goes forward, which is because ofloop: true
.So may I ask: Is there a reason why you use
loop: false
in your AutoPlay code and theninstead of just using
scrollNext()
withloop: true
?Considering the issue itself: Your solution with using
requestAnimationFrame
is without a doubt a much cleaner approach than being sloppy and just usingsetInterval()
like I did in the first place.So I don’t think it is necessary to actually try to fix this issue. However, I would suggest adding a CodeSandbox section as you’ve mentioned before, to make sure everyone interested in using Embla carousel for a slideshow gets pointed in the right direction concerning a proper implementation.
Does this make sense to you?