lightweight image comparison slider
How to build a responsive and lightweight image comparison slider using JavaScript
by Lalji Tadhani
HTML
<div class="image-slider-wrapper">
<div class="image-slider">
<div class="top-image">
<img src="https://source.unsplash.com/800x400?nature" alt="Nature" class="comparison-img after">
</div>
<img src="https://source.unsplash.com/800x400?tech" alt="Tech" class="comparison-img before">
<div class="handle"></div>
<input type="range" class="range-slider" min="0" max="100" value="50"/>
</div>
<div class="caption">
Move the slider to toggle a comparison between two images.
</div>
</div>
SCSS
.image-slider-wrapper {
max-width: 100%;
overflow: hidden;
margin: 30px auto;
.caption {
padding: 20px;
text-align: center;
font-size:14px;
opacity: .7;
}
}
.image-slider {
position: relative;
display: block;
width: 100%;
min-height: 600px;
height: 50vh;
display: flex;
align-content: flex-end;
> div {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 50%;
overflow: hidden;
display: flex;
align-items: flex-end;
}
.comparison-img {
display: block;
user-select: none;
box-sizing: border-box;
height: 100%;
width: 100%;
max-width: initial;
filter: grayscale(100%);
opacity: 0.5;
pointer-events: none;
object-fit: cover;
flex: none;
}
.top-image {
position: relative;
z-index: 10;
&:before {
content: "";
position: absolute;
top: 0;
right: 0;
width: 5px;
height: 100%;
border-right: 5px solid #FFF;
z-index: 20;
}
}
//this will act as the controller for the slider
.handle {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 20px;
background-color: #666666;
height: 80px;
border: 8px solid #FFF;
z-index: 30;
pointer-events: none;
margin-left: -2px;
overflow: visible;
&:before {
color: #FFF;
content: "";
position: absolute;
top: 25px;
right: -20px;
height: 10px;
width: 10px;
border-bottom: solid 3px currentColor;
border-right: solid 3px currentColor;
transform: rotate(-45deg);
z-index: 99;
}
&:after {
color: #FFF;
content: "";
position: absolute;
top: 25px;
left: -20px;
height: 10px;
width: 10px;
border-left: solid 3px currentColor;
border-top: solid 3px currentColor;
transform: rotate(-45deg);
z-index: 99;
}
}
input[type=range] {
margin: 0;
...
JavaScript
function imageSlider(elem) {
var imageContainer = elem;
var overlay = imageContainer.querySelector(".top-image");
var range = imageContainer.querySelector(".range-slider");
var images = imageContainer.querySelectorAll(".comparison-img");
var handle = imageContainer.querySelector(".handle");
images.forEach(function(elem) {
elem.style.width = range.offsetWidth + 'px'
})
range.oninput = function() {
if ( this.value > 0 ) {
overlay.style.width = this.value + "%";
handle.style.left = this.value + "%";
} else {
overlay.style.width = 'calc(0% + 5px)';
handle.style.left = 'calc(0% + 5px)';
}
}
}
const sliders = document.querySelectorAll('.image-slider-wrapper');
function initImageSliders() {
console.log('test')
for (var i = 0; i < sliders.length; i++) {
imageSlider(sliders[i]);
}
}
initImageSliders();
window.onresize = initImageSliders;
window.dispatchEvent(new Event('resize'));