Manual Implementation of Carousel

Implement carousel functionality using pure HTML, CSS, and JavaScript.

position

Use absolute and relative positioning with position to implement the carousel. First, concatenate all the images into a single row. Use overflow: hidden; to hide the other images. Add this row of images to a timer task that continuously moves them to the left, displaying only the middle image. Special handling is required for the edges. Append the first carousel image after the row of images. When switching to the last carousel image, the next image to be played is the first image. After this image carousel is complete, reset all the images. Two demos are provided: the first one is a simple carousel with no control buttons, and the second one is more comprehensive.

Example

<!-- 
    Simple demo, no controls, just image carousel 
-->

```html
<!DOCTYPE html>
<html>
<head>
    <title>Carousel</title>
    <meta charset="utf-8">
    <meta name="referrer" content="no-referrer">
</head>
<style type="text/css">
    body{
        margin: 0;
        padding: 0px;
    }
    #carousel{
        margin: auto; /* Center */
        width: 600px; /* Set width */
        position: relative; /* Relative positioning */
        overflow: hidden; /* Hide overflow */
    }
    #carousel img{
        width: 600px; /* Set size and scale proportionally */
    }
    #carousel > ul {
        display: flex; /* Display images in one row */
        position: absolute; /* Absolute positioning relative to #carousel */
    }
    #carousel > ul,
    #carousel > ul > li{
        padding: 0;
        margin: 0;
        list-style:none; 
    }
</style>
<body>
    <!-- Carousel container -->
    <div id="carousel">
        <ul> <!-- Image container -->
            <li>
                <img src="http://www.sdust.edu.cn/__local/9/7A/B1/F29B84DEF72DD329997E8172ABA_664BA3EF_32466.jpg">
            </li>
            <li>
                <img src="http://www.sdust.edu.cn/__local/B/F3/E4/693AB931C9FFB84646970D53BFE_C506394A_4282CA.jpg">
            </li>
            <li>
                <img src="http://www.sdust.edu.cn/__local/F/7A/AA/E1459849AA8AB0C89854A41BD41_BF3BD857_BC0D8.jpg">
            </li>
            <li>
                <img src="http://www.sdust.edu.cn/__local/1/95/CB/EDC1450B8FD1B8A25FAAC726AA4_A36D4253_16C91.jpg">
            </li>
        </ul>
    </div>
</body>
    <script type="text/javascript">
        var imgArr = []; // Array of images
        var curIndex = 0; // Current displayed image
        var timer = null; // Timer
        
        function slide(slideContainer){
            var width = imgArr[curIndex].width; // Get the width of the image, which is the distance to slide each time
            var distanceMoved = 0; // Distance already moved
            var step = 10; // Step of the slide
            var curConLeft = slideContainer.offsetLeft; // Get the left position of the ul
            var slideInterval = setInterval(function (){ // This timer is for the slide animation
                if(Math.abs(width - distanceMoved) > step){ // Boundary check, check the difference between the distance moved and the distance to move with the step
                    curConLeft -= step; // Move continuously if greater than the step
                    slideContainer.style.left = `${curConLeft}px`; // Move
                    distanceMoved += step; // Add the step to the distance moved
                }else{ 
                    clearInterval(slideInterval); // If the last distance moved is less than the step, clear the animation timer
                    slideContainer.style.left = `${curConLeft - width + distanceMoved }px`; // Complete the animation directly
                    distanceMoved = 0; // Reset the distance moved to 0
                    if(++curIndex === imgArr.length){ // Increment the index and check if it is the last image for edge handling
                        curIndex = 0; // Reset the index if it is the last image
                        slideContainer.style.left = 0;  // Reset the ul
                    }
                }
            }, 10);
        }
<body>
    <div id="carousel">
        <ul>
            <li>
                <img src="[to_be_replace1]">
            </li>
        </ul>
    </div>
    <div class="control">
        <span class="prev"></span>
        <span class="next"></span>
    </div>
</body>
</html>
<style type="text/css">
    body{
        margin: 0;
        padding: 0px;
    }
    #carousel{
        margin: auto;
        width: 600px;
        position: relative;
        overflow: hidden;
    }
    #carousel img{
        width: 600px;
    }
    #carousel > ul {
        display: flex;
        position: absolute;
    }
    #carousel > ul,
    #carousel > ul > li{
        padding: 0;
        margin: 0;
        list-style:none; 
    }
    .control{
        position: absolute;
        top: 50%;
        left: 0;
        right: 0;
        text-align: center;
        transform: translateY(-50%);
    }
    .control span{
        display: inline-block;
        width: 40px;
        height: 40px;
        background-color: rgba(0,0,0,0.5);
        color: #fff;
        font-size: 20px;
        line-height: 40px;
        cursor: pointer;
    }
    .control .prev{
        margin-right: 20px;
    }
    .control .next{
        margin-left: 20px;
    }
</style>
/* Control button style */
#leftArrow,
#rightArrow{
    position: absolute;
    left: 5px;
    top: 43%;
    width: 25px;
    height: 30px;
    background-color: #eee;
    display: flex;
    justify-content: center;
    align-items: center;
    opacity: 0.7;
    font-size: 20px;
    cursor: pointer;
}
#rightArrow{
    left: auto;
    right: 5px;
}
#sliderBtn{
    position: absolute;
    width: 100%;
    bottom: 0;
    display: flex;
    justify-content: flex-end;
}
.unitBtn{
    width: 10px;
    height: 10px;
    background-color: #eee;
    border-radius: 10px;
    margin: 10px;
    cursor: pointer;
}
.active{
    background-color: #4C98F7;
}
<body>
    <!-- Carousel container -->
    <div id="carousel">
        <ul> <!-- Image container -->
            <li>
                <img src="http://www.sdust.edu.cn/__local/9/7A/B1/F29B84DEF72DD329997E8172ABA_664BA3EF_32466.jpg">
            </li>
            <li>
                <img src="http://www.sdust.edu.cn/__local/B/F3/E4/693AB931C9FFB84646970D53BFE_C506394A_4282CA.jpg">
            </li>
            <li>
                <img src="http://www.sdust.edu.cn/__local/F/7A/AA/E1459849AA8AB0C89854A41BD41_BF3BD857_BC0D8.jpg">
            </li>
            <li>
                <img src="http://www.sdust.edu.cn/__local/1/95/CB/EDC1450B8FD1B8A25FAAC726AA4_A36D4253_16C91.jpg">
            </li>
        </ul>
        <!-- Button group -->
        <div id="leftArrow" class="iconfont icon-arrow-lift"></div> <!-- Left arrow switch button -->        
        <div id="rightArrow" class="iconfont icon-arrow-right"></div> <!-- Right arrow switch button --> 
        <div id="sliderBtn"></div> <!-- Switch button group -->
    </div>
</body>
<script type="text/javascript">
    var imgArr = []; // Image array
    var curIndex = 0; // Current displayed image
    var timer = null; // Timer
    var clickAllow = true; // Lock, whether the user is allowed to click
    var btnList = []; // Right bottom switch button group
    
    function slide(slideContainer , targetIndex = curIndex + 1){
        var width = 0; // Calculate the distance to slide for switching images
        if(targetIndex > curIndex){
            for(let i=curIndex;i<targetIndex;++i) width+=imgArr[i].width; // Calculate the width from the current image to the subsequent images for forward switching
        }else{
            if(targetIndex === -1) width = imgArr[imgArr.length-1].width; // Special handling for the first image
            else for(let i=targetIndex;i<curIndex;++i) width+=imgArr[i].width; // Handling for backward switching
        }
        clickAllow = false; // Do not allow the user to click
        var step = width/60; // Dynamically set the step size
        step = targetIndex > curIndex ? step : -step; // Forward or backward switching
        var curConLeft = slideContainer.offsetLeft; // Get the left position of the ul
        var distanceMoved = 0; // Distance already moved
        var slideInterval = setInterval(function (){ // This timer is used to implement the switching animation
            if(Math.abs(width - distanceMoved) > Math.abs(step)){ // Boundary judgment, compare the difference between the distance moved and the distance to be moved with the step size
                 curConLeft -= step; // Move continuously if the difference is greater than the step size
                slideContainer.style.left = `${curConLeft - step}px`; // Move
                distanceMoved += Math.abs(step); // Add the step size to the distance already moved
            }else{ 
                clearInterval(slideInterval); // If the last distance moved is less than the step size, clear the animation timer
                var directMove = step > 0 ? (curConLeft - width + distanceMoved) : (curConLeft + width - distanceMoved); // Calculation method for forward and backward movement is different
                slideContainer.style.left = `${directMove}px`; // Complete this animation directly
                distanceMoved = 0; // Reset the distance moved to 0
                curIndex = targetIndex; // Set the current index
                if(curIndex === imgArr.length){ // Increment the index and check if it is the last image for edge handling
                    curIndex = 0; // Reset the index
                    slideContainer.style.left = `-${imgArr[0].width}px`;  // Reset the ul
                }else if (curIndex === -1) {
                    curIndex = imgArr.length-1; // Reset the index for the first image
                    slideContainer.style.left = `-${slideContainer.offsetWidth - imgArr[imgArr.length-1].width - imgArr[0].width}px`;  // Reset the ul
                }
                switchBtnActive(); // Switch the right bottom button
                clickAllow = true; // Allow clicking
            }
        }, 10);
    }
</script>
function switchBtnActive() {
    btnList.forEach((v) => {
        v.className = "unitBtn"; // Set other buttons to gray
    })
    btnList[curIndex].className = "unitBtn active"; // Set the current button to blue
}

function createBtnGroup(carousel, slideContainer, config) {
    document.getElementById("leftArrow").addEventListener('click', (e) => {
        clearInterval(timer); // Clear the timer to avoid interference when manually switching
        if (clickAllow) slide(slideContainer, curIndex - 1); // Switch to the previous slide if allowed to click
        timer = setInterval(() => { slide(slideContainer) }, config.interval); // Reset the timer
    })
    document.getElementById("rightArrow").addEventListener('click', (e) => {
        clearInterval(timer); // Clear the timer to avoid interference when manually switching
        if (clickAllow) slide(slideContainer, curIndex + 1); // Switch to the next slide if allowed to click
        timer = setInterval(() => { slide(slideContainer) }, config.interval); // Reset the timer
    })
    var sliderBtn = document.getElementById("sliderBtn"); // Get a reference to the button container
    imgArr.forEach((v, i) => {
        let btn = document.createElement("div"); // Create a button
        btn.className = i === 0 ? "unitBtn active" : "unitBtn"; // Set the initial style of blue and gray buttons
        btn.addEventListener('click', (e) => {
            clearInterval(timer); // Clear the timer to avoid interference when manually switching
            if (clickAllow) slide(slideContainer, i); // Switch if allowed to click
            timer = setInterval(() => { slide(slideContainer) }, config.interval); // Reset the timer
        })
        btnList.push(btn); // Add the button to the button group
        sliderBtn.appendChild(btn); // Append the button to the button container
    })
}
function edgeDispose(slideContainer) {
  var li = document.createElement("li"); // Create <li>
  var img = document.createElement("img"); // Create new <img>
  img.src = imgArr[0].src; // Set image src
  li.appendChild(img); // Append <img> to <li>
  slideContainer.appendChild(li); // Append the first image to the end of the carousel for edge handling
  var li2 = document.createElement("li"); // Create <li>
  var img2 = document.createElement("img"); // Create new <img>
  img2.src = imgArr[imgArr.length - 1].src; // Set image src
  li2.appendChild(img2); // Append <img> to <li>
  slideContainer.insertBefore(li2, slideContainer.firstChild); // Append the last image to the beginning of the carousel for edge handling
  slideContainer.style.left = `-${imgArr[0].width}px`; // Reset the position of the carousel
}

function eventDispose(carousel, slideContainer, config) {
  document.addEventListener('visibilitychange', function() { // Listen for page visibility change to handle animation issues when switching pages
    if (document.visibilityState == 'hidden') clearInterval(timer); // Clear the timer when the page is hidden
    else timer = setInterval(() => { slide(slideContainer) }, config.interval); // Reset the timer
  });
  carousel.addEventListener('mouseover', function() { // Stop animation and timer when the mouse is over the carousel
    clearInterval(timer); // Clear the timer
  });
  carousel.addEventListener('mouseleave', function() { // Start animation when the mouse leaves the carousel
    timer = setInterval(() => { slide(slideContainer) }, config.interval); // Reset the timer
  });
}
(function start() {
    var config = {
        height: "300px", // Configure height
        interval: 5000 // Configure carousel interval
    }
    var carousel = document.getElementById("carousel"); // Get reference to container object
    carousel.style.height = config.height; // Set carousel container height
    document.querySelectorAll("#carousel img").forEach(v => imgArr.push(v)); // Get all images and create an array
    var slideContainer = document.querySelector("#carousel > ul"); // Get the ul container for the row of images
    edgeDispose(slideContainer); // Handle edge cases
    eventDispose(carousel,slideContainer,config); // Handle browser events
    createBtnGroup(carousel,slideContainer,config); // Handle button group
    timer = setInterval(() => {slide(slideContainer)},config.interval); // Set timer for automatic slide
})();
</script>
</html>

opacity

First, the images are stacked by using absolute positioning, and the opacity property is used to control the visibility of the images, so the image switching animation of the carousel is not controlled by JavaScript, but achieved using CSS animation. Since the images are stacked, using z-index is also a feasible solution.

Example

<!DOCTYPE html>
<html>
<head>
    <title>Carousel</title>
    <meta charset="utf-8">
    <meta name="referrer" content="no-referrer">
</head>
<link rel="stylesheet" type="text/css" href="https://at.alicdn.com/t/font_1582902_u0zm91pv15i.css">
<style type="text/css">
    body{
        margin: 0;
        padding: 0px;
    }
    #carousel{
        margin: auto; /* Center */
        width: 600px; /* Set width */
        position: relative; /* Relative positioning */
        overflow: hidden; /* Hide overflow */
    }
    #carousel img{
        position: absolute; /* Absolute positioning to stack images */
        width: 600px; /* Set size and scale proportionally */
        transition: all .6s; /* Animation */
        opacity: 0; /* Hide */
    }
    .imgActive{
        opacity: 1 !important; /* Show image with highest priority */
    }
/* Control button style */
#leftArrow,
#rightArrow{
    position: absolute;
    left: 5px;
    top: 43%;
    width: 25px;
    height: 30px;
    background-color: #eee;
    display: flex;
    justify-content: center;
    align-items: center;
    opacity: 0.7;
    font-size: 20px;
    cursor: pointer;
    z-index: 1000;
}
#rightArrow{
    left: auto;
    right: 5px;
}
#sliderBtn{
    position: absolute;
    width: 100%;
    bottom: 0;
    display: flex;
    justify-content: flex-end;
    z-index: 1000;
}
.unitBtn{
    width: 10px;
    height: 10px;
    background-color: #eee;
    border-radius: 10px;
    margin: 10px;
    cursor: pointer;
}
.btnActive{
    background-color: #4C98F7;
}
</style>
<body>
    <!-- Carousel container -->
    <div id="carousel">
        <img src="http://www.sdust.edu.cn/__local/9/7A/B1/F29B84DEF72DD329997E8172ABA_664BA3EF_32466.jpg">
        <img src="http://www.sdust.edu.cn/__local/B/F3/E4/693AB931C9FFB84646970D53BFE_C506394A_4282CA.jpg">
        <img src="http://www.sdust.edu.cn/__local/F/7A/AA/E1459849AA8AB0C89854A41BD41_BF3BD857_BC0D8.jpg">
        <img src="http://www.sdust.edu.cn/__local/1/95/CB/EDC1450B8FD1B8A25FAAC726AA4_A36D4253_16C91.jpg">
        <!-- Button group -->
        <div id="leftArrow" class="iconfont icon-arrow-lift"></div> <!-- Left arrow button -->
        <div id="rightArrow" class="iconfont icon-arrow-right"></div> <!-- Right arrow button -->
        <div id="sliderBtn"></div> <!-- Slider button group -->
    </div>
</body>
<script type="text/javascript">
    var imgArr = []; // Image array
    var curIndex = 0; // Current displayed image
    var timer = null; // Timer
    var btnList = []; // Bottom right slider buttons

    function slide(targetIndex = curIndex + 1){
        curIndex = targetIndex % imgArr.length; // Get current index
        imgArr.forEach((v) => v.className = "" ); // Hide other images
        imgArr[curIndex] .className = "imgActive"; // Display current image
        btnList.forEach(v => v.className = "unitBtn") // Set other buttons to gray
        btnList[curIndex] .className = "unitBtn btnActive"; // Set current button to blue
    }
function createBtnGroup(carousel, config) {
    document.getElementById("leftArrow").addEventListener('click', (e) => {
        clearInterval(timer); // Clear the timer to avoid interference when switching manually
        slide(curIndex - 1); // Switch to the previous image if allowed
        timer = setInterval(() => { slide() }, config.interval); // Reset the timer
    })
    document.getElementById("rightArrow").addEventListener('click', (e) => {
        clearInterval(timer); // Clear the timer to avoid interference when switching manually
        slide(curIndex + 1); // Switch to the next image if allowed
        timer = setInterval(() => { slide() }, config.interval); // Reset the timer
    })
    var sliderBtn = document.getElementById("sliderBtn"); // Get the reference to the button container
    imgArr.forEach((v, i) => {
        let btn = document.createElement("div"); // Create a button
        btn.className = i === 0 ? "unitBtn btnActive" : "unitBtn"; // Set the initial style of the button to blue or gray
        btn.addEventListener('click', (e) => {
            clearInterval(timer); // Clear the timer to avoid interference when switching manually
            slide(i); // Switch if allowed
            timer = setInterval(() => { slide() }, config.interval); // Reset the timer
        })
        btnList.push(btn); // Add the button to the button group
        sliderBtn.appendChild(btn); // Append the button to the button container
    })
}
function eventDispose(carousel, config) {
    document.addEventListener('visibilitychange', function() { // Listening to page switch when the browser switches pages will cause animation problems
        if (document.visibilityState == 'hidden') clearInterval(timer); // Clear the timer when the page is hidden
        else timer = setInterval(() => { slide() }, config.interval); // Reset the timer
    });
    carousel.addEventListener('mouseover', function() { // When the mouse moves to the container, the animation is not switched, and the timer is stopped
        clearInterval(timer); // Clear the timer when the page is hidden
    });
    carousel.addEventListener('mouseleave', function() { // When the mouse moves out of the container, the animation starts
        timer = setInterval(() => { slide() }, config.interval); // Reset the timer
    });
}


(function start() {
    var config = {
        height: "300px", // Configure the height
        interval: 5000 // Configure the carousel interval
    }
    var carousel = document.getElementById("carousel"); // Get a reference to the container object
    carousel.style.height = config.height; // Set the height of the carousel container
    document.querySelectorAll("#carousel img").forEach((v, i) => {
        imgArr.push(v); // Get all the images and create an array
        v.className = i === 0 ? "imgActive" : "";
    });
    eventDispose(carousel, config); // Handle some browser events
    createBtnGroup(carousel, config); // Handle the button group
    timer = setInterval(() => { slide() }, config.interval); // Set the timer to switch at regular intervals
})();

CSS

Pure CSS implementation of carousel, using CSS3 animation to complete the carousel, mainly using the animation property and @keyframes rule, using left to control the distance, or opacity, set the animation property for each image.

Example

<!DOCTYPE html>
<html>
<head>
    <title>Carousel</title>
    <meta charset="utf-8">
    <meta name="referrer" content="no-referrer">
</head>
<link rel="stylesheet" type="text/css" href="https://at.alicdn.com/t/font_1582902_u0zm91pv15i.css">
<style type="text/css">
    body{
        margin: 0;
        padding: 0px;
    }
    #carousel{
        margin: auto; /* Center */
        width: 600px; /* Set width */
        position: relative; /* Relative positioning */
        overflow: hidden; /* Hide overflow */
        height: 300px;
    }
    #carousel img{
        width: 600px; /* Set size and scale proportionally */
    }
    #carousel > ul {
        display: flex; /* Display images in a row */
        position: absolute; /* Set absolute positioning relative to #carousel */
    }
    #carousel > ul,
    #carousel > ul > li{
        padding: 0;
        margin: 0;
        list-style:none; 
    }

    #carousel > ul{
         animation: switch 10s ease 1s infinite alternate; /* Set animation */
    }

    #carousel > ul:hover{
         animation-play-state: paused; /* Pause animation on hover */
    }
<style>
@keyframes switch{ /* Define animation rules */
    0%,13%{
        left: 0;
    }
    27%,41%{
        left: -600px;
    }
    55%,69%{
        left: -1200px;
    }
    83%,100% {
        left: -1800px;
    }
}
</style>
<body>
    <!-- Carousel container -->
    <div id="carousel">
        <ul> <!-- Image container -->
            <li>
                <img src="http://www.sdust.edu.cn/__local/9/7A/B1/F29B84DEF72DD329997E8172ABA_664BA3EF_32466.jpg">
            </li>
            <li>
                <img src="http://www.sdust.edu.cn/__local/B/F3/E4/693AB931C9FFB84646970D53BFE_C506394A_4282CA.jpg">
            </li>
            <li>
                <img src="http://www.sdust.edu.cn/__local/F/7A/AA/E1459849AA8AB0C89854A41BD41_BF3BD857_BC0D8.jpg">
            </li>
            <li>
                <img src="http://www.sdust.edu.cn/__local/1/95/CB/EDC1450B8FD1B8A25FAAC726AA4_A36D4253_16C91.jpg">
            </li>
        </ul>
    </div>
</body>
</html>

Daily Question

https://github.com/WindrunnerMax/EveryDay