Infinite loop Scrolling Image Slider with buttons for navigation

How to create an infinite card/image slider that has a a smooth and uninterrupted slide that loops. Once a user interacts with slider, it should stop sliding and from then on only able to navigate by using prev/next buttons or drag-able on mobile. Should work like this https://codesandbox.io/s/embla-carousel-github-issue-105-i2gji?file=/src/js/EmblaCarousel.js or the gif bellow (with buttons for navigation) https://user-images.githubusercontent.com/273716/93586286-5e4abe00-f9a8-11ea-936b-6b09393e631a.gif
davidjerleke
CodeSandbox
Embla Carousel - Github Issue 105 - CodeSandbox
React version of Embla Carousel.
6 Replies
Zoë
Zoë15mo ago
It's late for me and I'm not going to do it right now but I can say the methods I might use and you can try it out. If you're stuck on how to achieve it Things that I have recognised you want (just to be clear and if I've missed anything) - Infinite scroll, and should support going left (things are easier if you can settle with infinite going right) - Scrolls automatically and stops after being hovered - Able to click/tap and drag to move while supporting links inside, and clicking those doesn't affect scrolling - The link you shared is not infinite and doesn't scroll by itself Method HTML layout
article //overflow-x: hidden
div //This is what is moved
section //These are the children with content inside
section
sec...
article //overflow-x: hidden
div //This is what is moved
section //These are the children with content inside
section
sec...
Using IntersectionObserver we can identify whether a child element is visible or not. The idea is that you have children and watch for the cards on the ends and if a child on the end is visible you move one from the other side. You can use absolute positioning or not use absolute positioning. Absolute positioning is a little simpler but there's the drawback of it being more difficult to be responsive as you can't get the heights of the children
Intersection Observer API - Web APIs | MDN
The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.
Zoë
Zoë15mo ago
Method : Absolute div will be position: relative with sections being position: absolute. When clicking and dragging you are moving the div and when you scroll such that one of the ends becomes visible you want to grab the element on the other side. If scrolling right you are bringing an element from the left to the right. You want to get the bounding box of the rightmost child and then set left of the moved child to left + width + gap If scrolling left you are bringing an element from the right to the left. You want to get the bounding box of the leftmost child and moved child. You want to set left of the moved child to left of leftmost child - gap - width Method : Non-Absolute div will be position: relative and display: flex. This method involves faking the position of the div to look like it's infinitely scrolling. You will be scrolling div but then shifting left when elements move, you never have a left greater than 0px and never less than the width of div - 100vw. If scrolling right you are bringing an element from the left to the right. Get the bounding box of the moved element, when you move the element also add the width to div. If scrolling left you are bringing an element from the right to the left. Get the bounding box of the moved element, when you move the element also subtract the width to div. Dragging You want to watch for the mousedown & touchstart (carousel), mouseup & touchend (document), mouseleave & touchcancel (document), and mousemove & touchmove (document) events. I will only talk about mouse from now on, but just know to do the same with the paired touch. When mousedown add the event listener for mousemove to the document, then when mouseup or mouseleave remove the event listener. You can either track the difference between the current x to the previous and then update (you will need to get this anyway), or you can track the x from mousedown and then subtract that from x from mousemove. For now just store the current x position that carousel should have, it will be used later. You will also want to track how fast the movement is if you want the carousel to continue spinning if you click, drag, and release while dragging. This is trickier than it seems because of the case where someone moves right and then at the last moment move left. The difference in x between each mousemove event is small, so you will need to store a few of the dx values as well as the difference in time. Then when it comes time to calculate the velocity you can add up the dx and the times and divide. You should work backwards and if values change from positive to negative or negative to positive stop looking, you just want the last direction. You also don't want to track too many points as it may make the movement sluggish. You only need to calculate the velocity when dragging stops, don't do it every mousemove. Play around and find a value that works. Movement mousemove causes a lot of updates and it's unnecessary to update the DOM for every event, so the actual movement will be handled when the browser says that it can. We can do that requestAnimationFrame. We will have a function that will tick every animation frame (if you want to be fancy you can stop and start this when it's still and when moving. When the velocity is 0 and not currently dragging you can just not call requestAnimationFrame and when you mousedown or touchstart you can start it again). Inside this function update the left of div to x Physics To have the carousel continue after releasing it we will use velocity. This velocity will continue to be added to x but at a diminishing rate. Physics should be handled inside the function for movement and only be active when not dragging. On each frame multiply velocity with a number like 0.99 (closer to 1 and it glides move, closer to 0 and it stops sooner. Just be aware that this number is multiplied a lot and so numbers are going to be fairly close to 1 even for something that feels like it has high friction). If you need further help and nobody else helps, I can help tomorrow
Zoë
Zoë15mo ago
It just needs some polish and set to move by default but I ran out of time. I started a bit late and only gave it 2 hours Fixes: - ✅ getting velocity needs to compare to current time, dragging, stopping, and releasing shouldn't result in movement - ✅ velocity seems a little inconsistent - ✅ move by default - touch doesn't work - breaks if you move it too far too fast It works exactly as I had described This is something that would require a couple days to get it perfect, and I've given it 4 hours. I'm going to be indisposed tomorrow and for a few days after. But this is one way to do it for when you make one yourself. Not allowing user interaction would make it far easier, just adding buttons would make it far easier, not having it be infinite would be a little easier.
marvxkiyi
marvxkiyiOP15mo ago
Hello Z, thank your very much for the help. I’ve spent my whole weekend on this, but unfortunately didn’t get that far. Your version looks cool, and am sure no one will scroll that much so it breaks 🤞🏿 i’ve unfortunately started my 9-5 and won’t be able to spend any time on this. Will have a glance at this, next weekend. If you happens to finish this before, could you ping me?
Zoë
Zoë15mo ago
I have no idea how long I'm going to be unable to work for, but this is something I want to polish, it's a lot of fun to work with
Want results from more Discord servers?
Add your server