Tự động phát băng chuyền

Băng chuyền này sử dụng tính năng chụp ảnh nhanh của CSS để tạo ra quá trình chuyển đổi trang trình bày mượt mà, hiệu quả mà không gây ra sự dịch chuyển bố cục.

Bạn có thể di chuyển trên băng chuyền này theo nhiều cách: ngoài các nút điều khiển điều hướng, băng chuyền này còn hỗ trợ thao tác di chuyển bằng bàn phím và vuốt. Để tối đa hoá khả năng hữu dụng và khả năng đọc, băng chuyền sẽ ngừng tự động chuyển đổi khi người dùng di chuột trong khu vực băng chuyền.

HTML

<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>

CSS


        #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;
}
        

JS


        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();