I am creating a store and on my landing page I want to create a touch-enabled slider/carousel with products (like the one on mobile https://www.nike.com/es).
I have created an overflowing container (.slider-container
) with 6 "product-slots" (.slide
) and I have set overflow
to scroll
in css. Now I want that whenever someone slides (touchmove
) a bit, it snaps to the next product once released (touchend
)
I have tried something in JS but I am an total amateur… (I don’t want to use SliderJs, etc. – trying to do it myself and learn a bit)
Here is HTML and CSS:
This is what I have tried on JS and basically, whenever you try to scroll, you get sent back to the beginning (slider.scrollLeft = 0
)
let startPos = 0
let sliderScroll = 0
let prevPos = 0
let currentPos = 0
const slider = document.querySelector('.slider-container')
const slideWidth = document.querySelector('.slide').getBoundingClientRect().width
function getPositionX(event) {
return
event.touches[0].clientX
}
function touchStart(event) {
startPos = getPositionX(event)
sliderScroll = slider.scrollLeft
}
function touchMove(event) {
currentPos = getPositionX(event)
}
function touchEnd() {
let calcNumber = Math.round((sliderScroll + Math.abs(startPos - currentPos)) / slideWidth)
let setScrollPos = calcNumber * slideWidth
slider.scrollTo({
left: setScrollPos,
behaviour: 'smooth'
})
}
slider.addEventListener('touchstart', touchStart)
slider.addEventListener('touchmove', touchMove)
slider.addEventListener('touchend', touchEnd)
*{
margin: 0;
padding: 0;
font-family: "Roboto Condensed", sans-serif;
}
html{
scroll-behavior:smooth;
overflow-x: hidden;
}
body {
overflow-x: hidden;
}
.slider-container{
display: flex;
overflow: scroll;
}
.slide{
min-width: 275px;
margin: 20px 0 40px 0;
padding-left: 10px;
}
.preview-product-title{
font-size: 17px;
padding: 2px 0 2px 0;
}
.preview-color{
font-size: 17px;
color: gray;
padding-bottom: 2px;
}
.preview-price{
font-size: 17px;
font-weight: bold;
}
.slide:first-child{
margin: 20px 0 40px 15px;
}
.slide:last-child{
margin: 20px 20px 40px 0;
}
<div class="slider-container">
<div class="slide">
<img src="https://picsum.photos/id/237/200/300" style="width: 275px;">
<p class="preview-product-title">Cool Shorts</p>
<p class="preview-color">Blue Navy</p>
<p class="preview-price">€29</p>
</div>
<div class="slide">
<img src="https://picsum.photos/id/25/200/300" style="width: 275px;">
<p class="preview-product-title">Cool Shorts</p>
<p class="preview-color">Blue Navy</p>
<p class="preview-price">€29</p>
</div>
<div class="slide">
<img src="https://picsum.photos/id/9/200/300" style="width: 275px;">
<p class="preview-product-title">Cool Shorts</p>
<p class="preview-color">Blue Navy</p>
<p class="preview-price">€29</p>
</div>
<div class="slide">
<img src="https://picsum.photos/id/237/200/300" style="width: 275px;">
<p class="preview-product-title">Cool Shorts</p>
<p class="preview-color">Blue Navy</p>
<p class="preview-price">€29</p>
</div>
<div class="slide">
<img src="https://picsum.photos/id/13/200/300" style="width: 275px;">
<p class="preview-product-title">Cool Shorts</p>
<p class="preview-color">Blue Navy</p>
<p class="preview-price">€29</p>
</div>
<div class="slide">
<img src="https://picsum.photos/id/10/200/300" style="width: 275px;">
<p class="preview-product-title">Cool Shorts</p>
<p class="preview-color">Blue Navy</p>
<p class="preview-price">€29</p>
</div>
</div>
2
Answers
To snap the touch slider to the scroll position using JavaScript, you can make the following adjustments to your code:
getPositionX
function to correctly return the clientX position.touchMove
function.scrollLeft
property instead ofscrollTo
method to set the scroll position.Here is the modified JavaScript code:
These modifications should help in achieving the snapping behavior you desire for your touch slider/carousel.
Your basic problem is that you have a return after your return:
This will return undefined. Correct is:
The next problem is then that you can’t scroll back. You need to remove the Math.abs:
Then you will find out that scrolling with touch has this inertia behaviour so it jumps but will keep scroll if you drag with enough speed. So it’s better to not use scrolling and scroll manually in your touch events and also mouse events. Also smooth scrolling with behaviour doesn’t work that well, but you can use the css setting scroll-behavior. But only while you’re not dragging.
Complete example:
I didn’t add inertia handling, that would be required or it feels a bit off and not as expected when you drag it with speed.