Carousel putar otomatis

Carousel ini menggunakan snap scroll CSS untuk membuat transisi slide yang lancar dan berperforma tinggi yang tidak menyebabkan pergeseran tata letak.

Carousel ini dapat dinavigasi dengan berbagai cara: selain kontrol navigasi, carousel mendukung navigasi dan geser keyboard. Untuk memaksimalkan kegunaan dan keterbacaan, carousel akan menghentikan transisi otomatis setelah pengguna menggerakkan mouse dalam area carousel.

<div id="carousel">
 
<div id="slide-container">
   
<div class="slide" data-slideIndex="0">
     
<div class="slide-banner">Tour the Empire State Building! <a href="">Buy tickets now.</a></div>
     
<img width="1200" height="600" src="./newyork.jpg">
   
</div>
   
<div class="slide" data-slideIndex="1">
     
<div class="slide-banner">Ride the Shinkansen! <a href="">Buy tickets now.</a></div>
     
<img width="1200" height="600" src="./tokyo.jpg">
   
</div>
   
<div class="slide" data-slideIndex="2">
     
<div class="slide-banner">Discover relaxation! <a href="">Buy tickets now.</a></div>
     
<img width="1200" height="600" src="./beach.jpg">
   
</div>
   
<div class="slide" data-slideIndex="3">
     
<div class="slide-banner">See penguins! <a href="">Buy tickets now.</a></div>
     
<img width="1200" height="600" src="./penguins.jpg">
   
</div>
   
<div class="slide" data-slideIndex="4">
     
<div class="slide-banner">Take a ride on the wheel! <a href="">Buy tickets now.</a></div>
     
<img width="1200" height="600" src="./wheel.jpg">
   
</div>
 
</div>
 
<div id="back-button" class="arrow back"></div>
 
<div id="forward-button" class="arrow forward"></div>
 
<div class="slide-indicators">
   
<div class="slide-indicator active"></div>
   
<div class="slide-indicator"></div>
   
<div class="slide-indicator"></div>
   
<div class="slide-indicator"></div>
   
<div class="slide-indicator"></div>
 
</div>
</div>

       
#carousel {
   
max-width: 1200px;
   
display: flex;
   
flex-direction: column;
   
margin: 0 auto;
   
position: relative;
}  
.slide-indicators {
   
display: flex;
   
justify-content: center;
}
.slide-indicator {
   
height: 44px;
   
width: 50px;
   
display: flex;
   
justify-items: center;
   
cursor: pointer;
}
.slide-indicator:after {
   
content: "";
   
background-color: #878787;
   
height: 10px;
   
margin-top: 10px;
   
width: 40px;
}
.slide-indicator.active:after,
.slide-indicator:hover:after {
   
background-color: #000;
}
.slide-banner {
   
background-color: #000;
   
color: #fff;
   
position: absolute;
   
left: 0;
   
bottom: 20px;
   
padding: 15px;
   
font-size: 2.5vw;
}
.slide-banner a {
   
color: #fff;
}
#slide-container {
   
scroll-snap-type: x mandatory;
   
overflow-x: scroll;
   
overflow-y: hidden;
   
display: flex;
   
align-items: center;
   
height: 100%;
   
gap: 10px;
   
-webkit-overflow-scrolling: touch;
   
scroll-behavior: smooth;
}
.slide {
   
scroll-snap-align: center;
   
position: relative;
   
min-width: 100%;
   
padding-top: 50%;
}
.slide img {
   
height: 100%;
   
width: auto;
   
position: absolute;
   
top: 0;
   
left: 0;
}
.arrow {
   
color: #fff;
   
height: 20px;
   
width: 20px;
   
background-color: #000;
   
position: absolute;
   
padding: 10px;
   
opacity: .3;
   
cursor: pointer;
}
.arrow.back {
   
left: 10px;
   
top: 10px;
}
.arrow.forward {
   
right: 10px;
   
top: 10px;
}
.arrow:hover {
   
opacity: 1;
}
       

       
function autoplayCarousel() {
   
const carouselEl = document.getElementById("carousel");
   
const slideContainerEl = carouselEl.querySelector("#slide-container");
   
const slideEl = carouselEl.querySelector(".slide");
    let slideWidth
= slideEl.offsetWidth;
   
// Add click handlers
    document
.querySelector("#back-button")
       
.addEventListener("click", () => navigate("backward"));
    document
.querySelector("#forward-button")
       
.addEventListener("click", () => navigate("forward"));
    document
.querySelectorAll(".slide-indicator")
       
.forEach((dot, index) => {
            dot
.addEventListener("click", () => navigate(index));
            dot
.addEventListener("mouseenter", () => clearInterval(autoplay));
       
});
   
// Add keyboard handlers
    document
.addEventListener('keydown', (e) => {
       
if (e.code === 'ArrowLeft') {
            clearInterval
(autoplay);
            navigate
("backward");
       
} else if (e.code === 'ArrowRight') {
            clearInterval
(autoplay);
            navigate
("forward");
       
}
   
});
   
// Add resize handler
    window
.addEventListener('resize', () => {
        slideWidth
= slideEl.offsetWidth;
   
});
   
// Autoplay
   
const autoplay = setInterval(() => navigate("forward"), 3000);
    slideContainerEl
.addEventListener("mouseenter", () => clearInterval(autoplay));
   
// Slide transition
   
const getNewScrollPosition = (arg) => {
       
const gap = 10;
       
const maxScrollLeft = slideContainerEl.scrollWidth - slideWidth;
       
if (arg === "forward") {
           
const x = slideContainerEl.scrollLeft + slideWidth + gap;
           
return x <= maxScrollLeft ? x : 0;
       
} else if (arg === "backward") {
           
const x = slideContainerEl.scrollLeft - slideWidth - gap;
           
return x >= 0 ? x : maxScrollLeft;
       
} else if (typeof arg === "number") {
           
const x = arg * (slideWidth + gap);
           
return x;
       
}
   
}
   
const navigate = (arg) => {
        slideContainerEl
.scrollLeft = getNewScrollPosition(arg);
   
}
   
// Slide indicators
   
const slideObserver = new IntersectionObserver((entries, observer) => {
        entries
.forEach(entry => {
           
if (entry.isIntersecting) {
               
const slideIndex = entry.target.dataset.slideindex;
                carouselEl
.querySelector('.slide-indicator.active').classList.remove('active');
                carouselEl
.querySelectorAll('.slide-indicator')[slideIndex].classList.add('active');
           
}
       
});
   
}, { root: slideContainerEl, threshold: .1 });
    document
.querySelectorAll('.slide').forEach((slide) => {
        slideObserver
.observe(slide);
   
});
}
autoplayCarousel
();