JSFiddle - React, Tailwind, and code Playground
CSS Variables based slider.
by Travis Almand
HTML
<div id="slider">
<div id="slides" data-slide="1">
<div class="slide" style='background-color: red;'>1</div>
<div class="slide" style='background-color: white;'>2</div>
<div class="slide" style='background-color: blue;'>3</div>
<div class="slide" style='background-color: green;'>4</div>
<div class="slide" style='background-color: yellow;'>5</div>
</div>
<div id="left" class="control"></div>
<div id="right" class="control"></div>
</div>
<br />
<input id="slide_num" type="number" />
<button id="pick_slide_num">choose</button>
CSS
:root {
--slide: 1;
--padding: 0;
--left: 0;
--slideWidth: 0;
}
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
html,
body {
margin: 0;
padding: 0;
}
#slider {
background-color: #000;
height: 300px;
overflow: hidden;
position: relative;
width: 100%;
}
#slides {
font-size: 0;
height: 100%;
transform: translate3d(calc(var(--slide) * var(--slideWidth) * -1 + var(--padding)), 0, 0);
transition: all 0.25s;
white-space: nowrap;
}
#slides:hover ~ .control {
opacity: 0.25;
}
#slides.leftStop ~ #left {
transform: translate3d(-100%, 0, 0);
}
#slides.rightStop ~ #right {
transform: translate3d(100%, 0, 0);
}
.slide {
box-shadow: inset 0 0 10px black;
display: inline-block;
font-size: 60px;
height: 100%;
line-height: 300px;
opacity: 0.25;
text-align: center;
transition: all 0.5s;
width: calc(100% * 0.8);
}
/* really wanted to do this by nth-child with a variable */
/* but a loop is necessary in JS */
.slide.active{
opacity: 1;
}
.control {
background-color: #fff;
cursor: pointer;
height: 100%;
left: 0;
opacity: 0;
position: absolute;
top: 0;
transition: all 0.15s;
width: 5%;
}
.control:hover {
opacity: 0.5;
}
#right {
left: auto;
right: 0;
}
JavaScript
var $slides = document.querySelector('#slides');
var $slide = Array.from(document.querySelectorAll('.slide'));
var $left = document.querySelector('#left');
var $right = document.querySelector('#right');
var $slideNum = document.querySelector('#slide_num');
var $pickSlideNum = document.querySelector('#pick_slide_num');
var slidesWidth = Math.round($slides.scrollWidth * 10) / 10;
var slideWidth = Math.round((slidesWidth / $slide.length) * 10) / 10;
var slide = parseInt($slides.dataset.slide) - 1;
var padding = Math.round((($slides.offsetWidth - slideWidth) / 2) * 10) / 10;
var left = -slide * slideWidth;
$slide[slide].classList.add('active');
document.documentElement.style.setProperty('--slide', slide);
document.documentElement.style.setProperty('--padding', padding + 'px');
document.documentElement.style.setProperty('--left', left + 'px');
document.documentElement.style.setProperty('--slideWidth', slideWidth + 'px');
function setActive() {
$slide.forEach(function (element, index) {
element.classList.remove('active');
if (index === slide) {
element.classList.add('active');
}
});
}
$slides.addEventListener('transitionend', function () {
$slides.classList.remove('leftStop', 'rightStop');
if (slide + 1 === 1) {
$slides.classList.add('leftStop');
} else if (slide + 1 === $slide.length) {
$slides.classList.add('rightStop');
}
});
$left.addEventListener('click', function () {
slide--;
setActive();
document.documentElement.style.setProperty('--slide', slide);
});
$right.addEventListener('click', function () {
slide++;
setActive();
document.documentElement.style.setProperty('--slide', slide);
});
$pickSlideNum.addEventListener('click', function () {
slide = $slideNum.value - 1;
if (slide >= 0 && slide <= $slide.length - 1) {
document.documentElement.style.setProperty('--slide', slide);
setActive();
}
});
//window.getComputedStyle(document.body).getPropertyValue('--base')