I'm building an image slider using HTML, CSS, and JS. It's running on a timer using JS and can also be scrolled through using navigation arrows when hovered over. I feel like it's almost done, but right now all the images are stuck next to each other in the viewport and I can't figure out how to space out the images so that only one shows in the viewport at a time.
I don't want the images to be 100% width, or else they'll be too big and they'll look bad (the slider is for brand logos). I just want each logo to be spaced out and centered within the viewport so there's only one logo showing at a time.
HTML:
<div class="image-slider">
<div class="image-slider__viewport">
<div class="image-slider__container">
<img src="https://i.postimg.cc/7hH1XLfK/checkout-logo-3-200x.webp" alt="eye logo" />
<img src="https://i.postimg.cc/Yh7J36fV/reef.webp" alt="reef logo" />
<img src="https://i.postimg.cc/F13M3Wc3/manduka.webp" alt="manduka logo" />
</div>
<div class="image-slider__navigation">
<button class="image-slider__navigation--prev">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
</svg>
</button>
<button class="image-slider__navigation--next">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
</svg>
</button>
</div>
</div>
</div>
CSS:
.image-slider {
width: 60%;
margin: auto;
}
.image-slider__viewport {
overflow: hidden;
position: relative;
width: 100%;
height: auto;
}
.image-slider__container {
display: flex;
align-items: center;
justify-content: center;
height: auto;
width: 100%;
transition: all 0.4s ease-in-out;
}
.image-slider__container img {
width: 100%;
height: auto;
max-width: 300px;
}
.image-slider__navigation {
width: 100%;
position: absolute;
left: 0;
top: 50%;
}
.image-slider__navigation--prev,
.image-slider__navigation--next {
position: absolute;
border: 0;
outline: 0;
width: 80px;
height: 80px;
cursor: pointer;
}
.image-slider__navigation--prev {
left: 0;
top: 50%;
transform: translateY(-50%);
}
.image-slider__navigation--next {
right: 0;
top: 50%;
transform: translateY(-50%);
}
JS:
const sliderViewport = document.querySelector(
'.image-slider__viewport'
);
const sliderImageContainer = sliderViewport.querySelector(
'.image-slider__container'
);
const numberOfSliderImages =
sliderImageContainer.querySelectorAll('img').length;
let slideOffset = 0;
const moveSlides = offset => {
const imageWidth =
sliderImageContainer.querySelector('img').offsetWidth;
sliderImageContainer.style.transform = `translateX(-${
offset * imageWidth
}px)`;
};
let timer;
const setTimer = () => {
timer = setInterval(() => {
slideOffset =
slideOffset < numberOfSliderImages - 1 ?
slideOffset + 1 :
0;
moveSlides(slideOffset);
}, 2000);
};
setTimer();
sliderViewport.addEventListener('mouseenter', () => {
clearInterval(timer);
});
sliderViewport.addEventListener('mouseleave', () => {
setTimer();
});
const prevButton = document.querySelector(
'.image-slider__navigation--prev'
);
const nextButton = document.querySelector(
'.image-slider__navigation--next'
);
prevButton.addEventListener('click', () => {
slideOffset =
slideOffset > 1 ?
slideOffset - 1 :
numberOfSliderImages - 1;
moveSlides(slideOffset);
});
nextButton.addEventListener('click', () => {
slideOffset =
slideOffset < numberOfSliderImages - 1 ?
slideOffset + 1 :
0;
moveSlides(slideOffset);
});
Here's the code for the slider. My guess is that it's a styling issue, and the CSS needs to be adjusted to make the images spaced out enough to show one at a time in the viewport. But I've tried messing around with the CSS and haven't had any success. I'm not exactly sure which part of the CSS needs to be adjusted either.
Here's a link to the JSFiddle: https://jsfiddle.net/t07mxkvw/3/
in your code, image-slider__container
has the same width of image-slider__viewport
. It means that you display all 3 images at once, and just transforming the width of image. So images are stuck.
I think this is what you want.
const sliderViewport = document.querySelector(".image-slider__viewport")
const sliderImageContainer = sliderViewport.querySelector(
".image-slider__container"
)
const numberOfSliderImages =
sliderImageContainer.querySelectorAll("img").length
let slideOffset = 0
const moveSlides = (offset) => {
const imageWidth =
sliderImageContainer.querySelector("img").parentElement.offsetWidth
sliderImageContainer.style.transform = `translateX(-${
offset * imageWidth
}px)`
}
let timer
const setTimer = () => {
timer = setInterval(() => {
slideOffset =
slideOffset < numberOfSliderImages - 1 ? slideOffset + 1 : 0
moveSlides(slideOffset)
}, 2000)
}
setTimer()
sliderViewport.addEventListener("mouseenter", () => {
clearInterval(timer)
})
sliderViewport.addEventListener("mouseleave", () => {
setTimer()
})
const prevButton = document.querySelector(
".image-slider__navigation--prev"
)
const nextButton = document.querySelector(
".image-slider__navigation--next"
)
prevButton.addEventListener("click", () => {
slideOffset =
slideOffset > 1 ? slideOffset - 1 : numberOfSliderImages - 1
moveSlides(slideOffset)
})
nextButton.addEventListener("click", () => {
slideOffset =
slideOffset < numberOfSliderImages - 1 ? slideOffset + 1 : 0
moveSlides(slideOffset)
})
const setImageSliderContainerWidth = () => {
const sliderViewport = document.querySelector(".image-slider__viewport")
const sliderImageContainer = sliderViewport.querySelector(
".image-slider__container"
)
const imageCount =
sliderImageContainer.getElementsByTagName("img").length
sliderImageContainer.style.width = `${
sliderViewport.offsetWidth * imageCount
}px`
}
window.onload = setImageSliderContainerWidth
window.onresize = setImageSliderContainerWidth
.image-slider {
width: 60%;
margin: auto;
}
.image-slider__viewport {
overflow: hidden;
position: relative;
width: 100%;
height: auto;
}
.image-slider__container {
display: flex;
align-items: center;
justify-content: center;
height: auto;
transition: all 0.4s ease-in-out;
}
.image-slider__container div {
width: 100%;
justify-content: center;
display: flex;
}
.image-slider__container img {
width: 100%;
height: auto;
max-width: 300px;
}
.image-slider__navigation {
width: 100%;
position: absolute;
left: 0;
top: 50%;
}
.image-slider__navigation--prev,
.image-slider__navigation--next {
position: absolute;
border: 0;
outline: 0;
width: 80px;
height: 80px;
cursor: pointer;
}
.image-slider__navigation--prev {
left: 0;
top: 50%;
transform: translateY(-50%);
}
.image-slider__navigation--next {
right: 0;
top: 50%;
transform: translateY(-50%);
}
<div class="image-slider">
<div class="image-slider__viewport">
<div class="image-slider__container" id="container">
<div>
<img
src="https://i.postimg.cc/7hH1XLfK/checkout-logo-3-200x.webp"
alt="eye logo"
/>
</div>
<div>
<img
src="https://i.postimg.cc/Yh7J36fV/reef.webp"
alt="reef logo"
/>
</div>
<div>
<img
src="https://i.postimg.cc/F13M3Wc3/manduka.webp"
alt="manduka logo"
/>
</div>
<div>
<img
src="https://i.postimg.cc/7hH1XLfK/checkout-logo-3-200x.webp"
alt="eye logo"
/>
</div>
<div>
<img
src="https://i.postimg.cc/Yh7J36fV/reef.webp"
alt="reef logo"
/>
</div>
<div>
<img
src="https://i.postimg.cc/F13M3Wc3/manduka.webp"
alt="manduka logo"
/>
</div>
</div>
<div class="image-slider__navigation">
<button class="image-slider__navigation--prev">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 19.5L8.25 12l7.5-7.5"
/>
</svg>
</button>
<button class="image-slider__navigation--next">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.25 4.5l7.5 7.5-7.5 7.5"
/>
</svg>
</button>
</div>
</div>
</div>
I added JS function to set image-slider__container
's width.
const setImageSliderContainerWidth = () => {
const sliderViewport = document.querySelector(".image-slider__viewport")
const sliderImageContainer = sliderViewport.querySelector(
".image-slider__container"
)
const imageCount =
sliderImageContainer.getElementsByTagName("img").length
sliderImageContainer.style.width = `${
sliderViewport.offsetWidth * imageCount
}px`
}