JSFiddle - React, Tailwind, and code Playground

by anoopsuda

HTML

<h2>Eight images, with 80px gap</h2>
<div class="carousel" data-gap="80">
	<figure>
    <img src="https://source.unsplash.com/VkwRmha1_tI/800x533" alt="">
		<img src="https://source.unsplash.com/EbuaKnSm8Zw/800x533" alt="">
		<img src="https://source.unsplash.com/kG38b7CFzTY/800x533" alt="">
		<img src="https://source.unsplash.com/nvzvOPQW0gc/800x533" alt="">
		<img src="https://source.unsplash.com/mCg0ZgD7BgU/800x533" alt="">
		<img src="https://source.unsplash.com/1FWICvPQdkY/800x533" alt="">
		<img src="https://source.unsplash.com/bjhrzvzZeq4/800x533" alt="">
		<img src="https://source.unsplash.com/7mUXaBBrhoA/800x533" alt="">
	</figure>
	<nav>
		<button class="nav prev">Prev</button>
		<button class="nav next">Next</button>
	</nav>
</div>

CSS

body {
	 margin: 0;
	 font-family: 'Roboto', sans-serif;
	 font-size: 16px;
}
 h1 {
	 text-align: center;
	 margin-bottom: 1.5em;
}
 h2 {
	 text-align: center;
	 color: #555;
	 margin-bottom: 0;
}
 .carousel {
	 padding: 20px;
	 perspective: 500px;
	 overflow: hidden;
	 display: flex;
	 flex-direction: column;
	 align-items: center;
}
 .carousel > * {
	 flex: 0 0 auto;
}
 .carousel figure {
	 margin: 0;
	 width: 40%;
	 transform-style: preserve-3d;
	 transition: transform 0.5s;
}
 .carousel figure img {
	 width: 100%;
	 box-sizing: border-box;
	 padding: 0 0px;
}
 .carousel figure img:not(:first-of-type) {
	 position: absolute;
	 left: 0;
	 top: 0;
}
 .carousel nav {
	 display: flex;
	 justify-content: center;
	 margin: 20px 0 0;
}
 .carousel nav button {
	 flex: 0 0 auto;
	 margin: 0 5px;
	 cursor: pointer;
	 color: #333;
	 background: none;
	 border: 1px solid;
	 letter-spacing: 1px;
	 padding: 5px 10px;
}

JavaScript

window.addEventListener('load', () => {
	var
		carousels = document.querySelectorAll('.carousel')
	;

	for (var i = 0; i < carousels.length; i++) {
		carousel(carousels[i]);
	}
});

function carousel(root) {
	var
		figure = root.querySelector('figure'),
		nav = root.querySelector('nav'),
		images = figure.children,
		n = images.length,
		gap = root.dataset.gap || 0,
		bfc = 'bfc' in root.dataset,
		
		theta =  2 * Math.PI / n,
		currImage = 0
	;
	
	setupCarousel(n, parseFloat(getComputedStyle(images[0]).width));
	window.addEventListener('resize', () => { 
		setupCarousel(n, parseFloat(getComputedStyle(images[0]).width)) 
	});

	setupNavigation();

	function setupCarousel(n, s) {
		var	
			apothem = s / (2 * Math.tan(Math.PI / n))
		;
		
		figure.style.transformOrigin = `50% 50% ${- apothem}px`;

		for (var i = 0; i < n; i++)
			images[i].style.padding = `${gap}px`;
		for (i = 1; i < n; i++) {
			images[i].style.transformOrigin = `50% 50% ${- apothem}px`;
			images[i].style.transform = `rotateY(${i * theta}rad)`;
		}
		if (bfc)
			for (i = 0; i < n; i++)
				 images[i].style.backfaceVisibility = 'hidden';
		
		rotateCarousel(currImage);
	}

	function setupNavigation() {
		nav.addEventListener('click', onClick, true);
		
		function onClick(e) {
			e.stopPropagation();
			
			var t = e.target;
			if (t.tagName.toUpperCase() != 'BUTTON')
				return;
			
			if (t.classList.contains('next')) {
				currImage++;
			}
			else {
				currImage--;
			}
			
			rotateCarousel(currImage);
		}
			
	}

	function rotateCarousel(imageIndex) {
		figure.style.transform = `rotateY(${imageIndex * -theta}rad)`;
	}
	
}