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