How To Create a Before and After Image Slider With Vanilla JavaScript
Tags: javascript, webdev, beginners, tutorial
Published: 2023-12-01 08:58:18

In the field of web development, user engagement and interactive design play pivotal roles in creating a memorable online experience. One powerful technique that captivates audiences and tells compelling visual stories is the Before-and-After Image Slider. 

This component allows users to seamlessly compare two images by sliding between them, unveiling transformations, enhancements, or the passage of time. In this guide, you will learn how to build the image slider using just HTML, CSS, and Vanilla JavaScript.

## Setting Up The Development Environment
To get started, create a new folder. On UNIX systems and Windows, you can do so with the **mkdir** command. In this folder, add the following files: **index.js**, **index.html** and **app.css**. Open the **index.html** file and add the following starter code:
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="app.css" />
    <title>Before and After Image Slider</title>
  </head>
  <body>
    <h1>Before and After Image Slider</h1>
    <form>
      Add "before" image:
      <input type="file" accept="image/*" name="" id="before-selector" onchange="updateImage()"/>
      <br />
      Add "after" image:
      <input type="file" accept="image/*" name="" id="after-selector" onchange="updateImage()"/>
    </form>
    <div class="image-container">
      <input type="range" name="" id="" min="0" max="100" value="50" tabindex="-1"/>
      <div class="image-after"></div>
      <div class="image-before"></div>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```
In the code block above, there is **form** element that holds two **input** elements, with each one of them having an **onchange** event handler that calls an **updateImage()** function. 

Next, you have an "image-container" **div**, that holds three additional elements, a "range" **input** element and two **divs** that will hold the "before" and "after" image respectively.

The **input** element with type "range", has a default value of 50, and the **tabindex** attribute is there to ensure that the **input** element does not receive tab focus.

## Adding Some Styling
Right now everything looks bland, so open up the **app.css** file, and add the following:
```css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 10px;
}

body {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

.image-container {
  display: flex;
  margin-top: 10px;
  height: 700px;
  width: 1015px;
  background-color: transparent;
}

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  position: absolute;
  width: inherit;
  padding: 0px;
  margin-top: 360px;
  z-index: 100;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  border-radius: 50%;
  margin-top: -10px;
  background-color: white;
  cursor: grab;
  height: 1.1rem;
  width: 1.1rem;
}

input[type="range"]::-webkit-slider-thumb:active {
  background-color: rgb(231, 227, 227);
  cursor: grabbing;
}

.image-before {
  position: absolute;
  padding: 0;
  margin-left: 8.5px;
  background-image: url("https://cdn.pixabay.com/photo/2023/08/16/23/47/annas-hummingbird-8195150_1280.jpg");
  background-repeat: no-repeat;
  background-size: cover;
  box-shadow: 5px 0px 9px 1px #fffefe11;
  height: inherit;
  width: 1000px;
  z-index: 10;
  border-right: solid 0.5px rgba(255, 255, 255, 0.425);
}

.image-after {
  position: absolute;
  margin-left: 8.5px;
  background-image: url("https://cdn.pixabay.com/photo/2016/11/23/18/27/hummingbird-1854225_640.jpg");
  background-repeat: no-repeat;
  background-size: cover;
  height: inherit;
  width: 1000px;
  /* z-index: -10; */
}
```

From the CSS above, there are four important things you should pay attention to: The styling for the **input** element of type "range",**image-container** and **image-before** and **image-after**.

The **image-before** and **image-after** divs have their positions set to **absolute**, with **image-before** overlaying **image-after**. This is important because it helps sell the illusion of a smooth transition between images as the user moves the slider.

The "range" **input** element is important because you can hook onto it with JavaScript and use the "value" attribute, to determine how wide an image should be. Notice how the default styling for **input[type='range']** is overridden with **appearance: none**.

## Making Things Functional With JavaScript
Moving on to JavaScript, open the **index.js** file, select all the necessary elements from the Document Object Model (DOM), and bind them to variables, like this:
```js
let slider = document.querySelector("input[type='range']");
let beforeImage = document.querySelector(".image-before");
let afterImage = document.querySelector(".image-after");
let beforeSelector = document.querySelector("#before-selector");
let afterSelector = document.querySelector("#after-selector");
```
Next, using the **getComputedStyle** function, retrieve the width of **beforeImage** and bind it to the **beforeImageWidth** variable. Remember that **getComputedStyle** returns the width alongside its unit (which you do not need in this case). In this case, since the unit is "px", you can use the **slice** method to remove the unwanted unit like this:
```js
let beforeImageWidth = getComputedStyle(beforeImage).width.slice(
  0,
  getComputedStyle(beforeImage).width.indexOf("p")
);
```
Next, add an event listener to **slider** that will listen for "input" events on the element. In the event listener's callback function, call the **updateImage** function and pass in the target element as a parameter:
```js
slider.addEventListener("input", (e) => {
  adjustImage(e.target);
});
```
Finally, add define the **adjustImage** function like this:
```js
function adjustImage(target) {
  beforeImage.style.width = `${(target.value / 100) * beforeImageWidth}px`;
}
```
In the code block above, the **adjustImage** function takes in the **target** parameter and uses the **value** property to modify the width of **beforeImage**. 

Finally, call the **adjustImage** function, and pass in **slider** as a parameter. This will ensure consistency by automatically setting the width of **beforeImage** on page load:
```js
adjustImage(slider);
```

## Taking Things Further By Adding Upload Functionality.
The image slider works fine, but right now, there is no way to modify the before and after images without digging through the **app.css** file and modifying the hard-coded values in the **background** properties of **image-before** and **image-after**. To make things dynamic, create an **updateImage** function like this:
```js
function updateImage(){

}
```
Check if **#beforeSelector** contains any files, then instantiate the **FileReader** object and call the **readAsDataURL** method.
```js
if (beforeSelector.files && beforeSelector.files[0]) {
  const reader = new FileReader();
  reader.onload = function (e) {
    // Display the selected image
    beforeImage.style.background = `url("${e.target.result}")`;
  };
  reader.readAsDataURL(beforeSelector.files[0]);
}
```
Do the same for **#afterSelector**, like this:
```js
if (afterSelector.files && afterSelector.files[0]) {
  const reader = new FileReader();
  reader.onload = function (e) {
    // Display the selected image
    afterImage.style.background = `url("${e.target.result}")`;
  };
  reader.readAsDataURL(afterSelector.files[0]);
}
```
Returning to the browser, you should be able to select the before and after images from the front end, without needing to modify the hard-coded CSS values:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wayog1t1mkma9h2vg9bg.png)

## Things To Consider When Building An Image Slider
While this guide covered the basics, in a real-world application, there are many things to consider when building an image slider, like responsive design, support for touch gestures, and accessibility.

Note that not all users are the same, and you should always strive to provide alternatives for users with disabilities, even if it comes at the cost of aesthetics. Lastly, keep it simple and focused – don't overwhelm your audience with too many images or flashy transitions. Striking the right balance between aesthetics and functionality is the secret sauce for an effective image slider.