Alexandre Buleté - image d'horloge
5 min 23 May 2022

Build an image slider in less than 2 minutes

Probably one of the most essential element of the web: slider! Are you a beginner and don’t know how to build one? Are you an experienced developer but want to find a faster solution from scratch?

In that case read this article it might help you 😉

We’ll just need some CSS and a pinch of JavaScript (vanilla of course).

For information before to start, in this article I will represent the list of images and points in a PHP loop and the CSS will be in SCSS.

First step: build the slider skeleton.

1/ Create the HTML slider structure

<div class="image-slider">
    <div class="slider--container">
        <div class="prev-btn"><</div>
        <div class="next-btn">></div>
        <div class="slider--content" position="1" style="left:0%">
            <?php foreach($imgs as $img): ?>
                <img 
                    src="<?= $img['url'] ?>" 
                    alt="<?= $img['alt'] ?>" 
                >
        </div>
    </div>
    <ul class="dots">
        <?php for($i=0; $i < count($imgs); $i++): ?>
            <li 
                class="dot <?= $i === 0 ? 'current' : '' ?>"
                pos="<?= $i ?>"
            >
            </li>
        <?php endfor; ?>
    </ul>
</div>

Here we start by setting up a div.image-slider where we add 2 elements:

  • div.slider--container tag will contains our arrows (to play the next and previous frames) and the images list.
  • ul.dots tag which will be our dots list (under the slider). It will will also allow us to move from one image to another.

You will also notice the style attribute with a left: 0% for the .slider–content.
Remember it because it is an important point in the construction of our script.

Once the HTML is in place, we will apply the style to it.

2/ Apply the style

$grey-20 : #CCC;
$grey-60 : #666;

.image-slider {
    .slider--container {
        position: relative;
        overflow: hidden;
        .slider--content {
            positon: relative;
            display: flex;
            transition: all .4s ease;
            img {
                width: 100%;
                box-sizing: border-box;
                border: 1px solid $grey-20;
                flex-shrink: 0;
            }
        }
        .prev-btn, .next-btn {
            z-index: 1;
            position: absolute;
            top: 0;
            bottom: 0;
            width: 70px;
            display: grid;
            justify-content: center;
            align-content: center;
            font-size: 36px;
            font-weight: 200;
            cursor: pointer;
            background: rgba(white, .5);
            box-shadow: 0 0 15px rgba(black, .1);
            transition: all .4s ease;
        }
        .prev-btn {
            left:-100px;
        }
        .next-btn {
            right:-100px;
        }
        &:hover {
            .prev-btn {
                left:0;
            }
            .next-btn {
                right:0;
            }
        }
    }
    .dots {
        display: flex;
        justify-content: center;
        padding-top: 10px;
        margin-top: 10px;
        .dot {
            cursor: pointer;
            height: 10px;
            width: 10px;
            border: 1px solid $grey-20;
            border-radius: 50px;
            margin: 0 4px;
            box-sizing: border-box;
            &.current {
                background: $grey-60;
            }
        }
    }
}

In this css the flex-shrink: 0 is not necessary on an img type element but you will need it if, for example, you wrap your images in a div, it will allow the slider to go out of the page and window and not restrict them inside their content.

3/ The script

let sliderSections = document.querySelectorAll('.image-slider')

if (sliderSections.length) {
    sliderSections.forEach(slider => {
        let imgs = slider.querySelectorAll('img')
        let content = slider.querySelector('.slider--content')
        let pos = content.getAttribute('position')
        let length = imgs.length
        let prevBtn = slider.querySelector('.prev-btn')
        let nextBtn = slider.querySelector('.next-btn')
        let dots = slider.querySelectorAll('.dots .dot')
        nextBtn.addEventListener('click', () => {
            if (pos < length) {
                let res = content.style.left.replace('%', '') - 100
                content.setAttribute('style', `left:${res}%`)
                pos++
                setDots(dots, pos)
                content.setAttribute('position', pos)
            }
        })
        prevBtn.addEventListener('click', () => {
            if (pos > 1) {
                let res = parseInt(content.style.left.replace('%', '')) + 100
                content.setAttribute('style', `left:${res}%`)
                pos--
                setDots(dots, pos)
                content.setAttribute('position', pos)
            }
        })
        dots.forEach( dot => {
            dot.addEventListener('click', () => {
                dot.classList.remove('current')
                let p = dot.getAttribute('pos')
                let res = parseInt(p) * 100
                content.setAttribute('style', `left:-${res}%`)
                p++
                setDots(dots, p)
                content.setAttribute('position', p)
            })
        })
    })
}

function setDots(dots, pos) {
    console.log(pos)
    dots.forEach(dot => {
        dot.classList.remove('current')
    })
    dots[pos - 1].classList.add('current')
}

First we define all the sliders in a querySelectorAll() then we check if there is at least one on the page (to avoid errors in the console).

Then for each slider found we perform our animation.

The position is retrieved in the “position” attribute of our .slider–content which is initially “1”.

We then compare this position when clicking on the scrolling arrows in order to verify that we do not exceed the display limits of our slider.

Once this condition is valid, we modify the left style (which I mentioned earlier) in order to scroll the content of the slider.

Then we assign the new position value to our element and we call the setDots() function which allows us to style the point of the new position.