CSS flex allows to lay elements in a single direction, either horizontally or vertically. Items in a slider / carousal are placed horizontally — going by this condition, CSS flex is a well suited candidate for creating a slider.
Using flexbox to create a slider is not difficult, however the main issue is to repeat items while looping the slider. For example, after the last item we would like the first item to again come in. Or if moving in right direction, after the first item goes out, the last item should come in.
To achieve this requires changing the order property for all flexbox items right after an item finishes its sliding movement (this can be detected using transitionend or animationend Javascript event).
The item that slides inside is set with order: 1. The element that should come in next is set with order: 2 and so on. This needs to be set with Javascript.
This tutorial only explains left-side movement, for code simplicity. Right-side movement can also be achieved with similar logic.
Example
HTML, CSS & Javascript
<div id="slider-container-outer">
<div id="slider-container" class="slider-container-transition">
<div class="slider-item" data-position="1">Item 1</div>
<div class="slider-item" data-position="2">Item 2</div>
<div class="slider-item" data-position="3">Item 3</div>
<div class="slider-item" data-position="4">Item 4</div>
</div>
</div>
<button id="move-button">Move Item</button>
#slider-container-outer {
overflow: hidden;
}
#slider-container {
display: flex;
flex-wrap: nowrap;
flex-direction: row;
}
/* CSS transition applied when translation of items happen */
.slider-container-transition {
transition: transform 0.7s ease-in-out;
}
.slider-item {
width: 100%;
flex-shrink: 0;
}
const FlexSlider = {
// total no of items
num_items: document.querySelectorAll(".slider-item").length,
// position of current item in view
current: 1,
init: function() {
// set CSS order of each item initially
document.querySelectorAll(".slider-item").forEach(function(element, index) {
element.style.order = index+1;
});
this.addEvents();
},
addEvents: function() {
var that = this;
// click on move item button
document.querySelector("#move-button").addEventListener('click', () => {
this.gotoNext();
});
// after each item slides in, slider container fires transitionend event
document.querySelector("#slider-container").addEventListener('transitionend', () => {
this.changeOrder();
});
},
changeOrder: function() {
// change current position
if(this.current == this.num_items)
this.current = 1;
else
this.current++;
let order = 1;
// change order from current position till last
for(let i=this.current; i<=this.num_items; i++) {
document.querySelector(".slider-item[data-position='" + i + "']").style.order = order;
order++;
}
// change order from first position till current
for(let i=1; i<this.current; i++) {
document.querySelector(".slider-item[data-position='" + i + "']").style.order = order;
order++;
}
// translate back to 0 from -100%
// we don't need transitionend to fire for this translation, so remove transition CSS
document.querySelector("#slider-container").classList.remove('slider-container-transition');
document.querySelector("#slider-container").style.transform = 'translateX(0)';
},
gotoNext: function() {
// translate from 0 to -100%
// we need transitionend to fire for this translation, so add transition CSS
document.querySelector("#slider-container").classList.add('slider-container-transition');
document.querySelector("#slider-container").style.transform = 'translateX(-100%)';
}
};
FlexSlider.init();
- Every time an item needs to come in, the slider container is translated from 0 to -100% (with sliding animation).
- Every time an item finishes coming in, the CSS order for items needs to be changed. However changing order will change the current displayed item as well. To negate this, slider container is translated back, from -100% to 0 (with no animation).
- The item that moves in has order as 1. The next item that should come will have order as 2. And so on.