NoLoJS logo

Image Comparison Slider - Custom Handle

Same as the Basic, but with some UI customization.

Demo

Sample image, rugged sunlit cliffsides with bright blue sky above

HTML

<!-- The important part here is the `.container`, two children with an image, and the `range` element -->
<div class="container custom-handle">
  <div id="left">
    <img src="https://images.unsplash.com/photo-1763236390948-fcc866ddb17a?crop=entropy&cs=srgb&fm=jpg&ixid=M3wzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3Njk3MTQ1MjB8&ixlib=rb-4.1.0&q=85&w=800" 
      width="800"
      height="533"
      alt="Sample image, rugged sunlit cliffsides with bright blue sky above" />
  </div>
  <div id="right">
    <img src="https://images.unsplash.com/photo-1763236390948-fcc866ddb17a?crop=entropy&cs=srgb&fm=jpg&ixid=M3wzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3Njk3MTQ1MjB8&ixlib=rb-4.1.0&q=85&w=800&colorquant=2" 
      width="800" 
      height="533"
      alt="Sample image, rugged rock being battered by waves with pastel sky above" />
  </div>
  <input type="range">
</div>

CSS

/* Basic slider */
.container {
  position: relative;
  max-width: 800px;
  height: auto;
  aspect-ratio: 6 / 4;
  display: grid;
  place-items: center;
  overflow: hidden;
}
/* Overlap the image containers, and stretch the images to fill the container */
div div {
  position: absolute;
  height: 100%;
  left: 0;
  right: 0;
}
img {
  height: 100%;
  object-fit: cover;
}
div div {
  position: absolute;
  height: 100%;
  left: 0;
  right: 0;
}
#left img {
  object-position: 0 0;
}
#right img {
  object-position: 100% 0;
}
/* Setup the `range` element */
input {
  --thumb-width: 17px;
  width: calc(100% + var(--thumb-width));
  z-index: 1;
}

/* Set the anchor position */
#right {
  left: anchor(--thumb center);
}

/* Attach the slider handle to the anchor*/
input::-webkit-slider-thumb {
  anchor-name: --thumb;
}
input::-moz-range-thumb {
  anchor-name: --thumb;
}
input::-ms-thumb {
  anchor-name: --thumb;
}

/* Add the fancy handle */
.custom-handle {
  /* Customize the `range` element */
  input {
    /* Effectively hide the track */
    -webkit-tap-highlight-color: transparent;
    -webkit-appearance: none;
    appearance: none;
    background-color: transparent;
    /* Allow the user to grab the handle anywhere along the dividing line */
    height: 100%;
    /* Use the "resize" cursor to make the action more intuitive */
    cursor: col-resize;
  }
  /* Give the handle a more obvious demarcation */
  #right {
    outline: 2px solid rgb(255 255 255 / .5);
    border-left: 2px solid rgb(255 255 255 / .5);
  }
  /* Customize the hdnale itself */
  input::-webkit-slider-thumb {
    /* Effectively hide the initial look */
    -webkit-tap-highlight-color: transparent;
    -webkit-appearance: none;
    appearance: none;
    /* Make sure the handle is easy to grab */
    width: 40px;
    height: 40px;
    /* Add double-arrow SVG icon */
    background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20class%3D%22compare__icon%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M%206%202%20L%201%208%20L%206%2014%20M%2010%202%20L%2015%208%20L%2010%2014%22%20stroke%3D%22currentColor%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
    /* Further customize the appearance */
    background-color: white;
    background-position: center;
    background-repeat: no-repeat;
    background-size: 70%;
    border-radius: 100%;
  }
  /* Above has to be repeated separately for Mozilla... */
  input::-moz-range-thumb {
    /* Make sure the handle is easy to grab */
    width: 40px;
    height: 40px;
    /* Add double-arrow SVG icon */
    background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20class%3D%22compare__icon%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M%206%202%20L%201%208%20L%206%2014%20M%2010%202%20L%2015%208%20L%2010%2014%22%20stroke%3D%22currentColor%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
    /* Further customize the appearance */
    background-color: white;
    background-position: center;
    background-repeat: no-repeat;
    background-size: 70%;
    border-radius: 100%;
  }
  /* And Edge. */
  input::-ms-thumb {
    /* Make sure the handle is easy to grab */
    width: 40px;
    height: 40px;
    /* Add double-arrow SVG icon */
    background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20class%3D%22compare__icon%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M%206%202%20L%201%208%20L%206%2014%20M%2010%202%20L%2015%208%20L%2010%2014%22%20stroke%3D%22currentColor%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E);
    /* Further customize the appearance */
    background-color: white;
    background-position: center;
    background-repeat: no-repeat;
    background-size: 70%;
    border-radius: 100%;
  }
}

JS

No JS required.

Baseline

[`anchor-positioning`](https://webstatus.dev/features/anchor-positioning)

CodePen

See the Pen on CodePen.