Recently a production artist from Orchard Film Studios, inspired by my recent explorations into before-and-after comparison sliders for images, wrote to me with an interesting question: could the same effect be achieved with video? They provided two samples (shown in the example above) and I set to work.
At first, the solutions I came up with seemed rather complex: my initial thought was to take the feeds from the before and after videos and pipe them into a <canvas>
element, moving the divisor there. While an intriguing possibility – and one that I eventually succeeded in achieving - I found that my initial experiments suffered badly in both performance and UI.
The biggest challenge was that variations of my original technique seemed not to apply: my earlier responsive solutions had all depended on the fact that a background image could be scaled alongside a real <img>
using background-size: cover
, but video can’t be made into a background, at least not without some hacks.
Then I had a moment of insight. What if I scaled one of the videos opposite to the slider effect? The code could start off very much the same as earlier comparators:
<div id="video-compare-container">
<video loop autoplay poster="dirty.jpg">
<source src="floodplain-dirty.mp4">
<source src="floodplain-dirty.webm">
</video>
<div id="video-clipper">
<video loop autoplay poster="clean.jpg">
<source src="floodplain-clean.mp4">
<source src="floodplain-clean.webm">
</video>
</div>
</div>
The “before” video content is in the “base” container, while the “after” content is nested within another <div>
inside that. I prototyped a quick stylesheet:
#video-compare-container {
display: inline-block;
line-height: 0;
position: relative;
}
#video-compare-container > video {
width: 100%;
height: auto;
}
#video-clipper {
width: 50%;
position: absolute;
top: 0;
bottom: 0;
overflow: hidden;
}
#video-clipper video {
width: 100%;
}

The problem is that the inner video would shrink to fit the reduced size of its #video-clipper
container. My thought was to increase the size of the <video>
element to compensate: if #video-clipper
was half the size of its parent element, the <video>
inside it would have to be twice its normal size to look correct. To test this, I added a temporary declaration to the end of the initial CSS:
#video-clipper video { width: 200%; }
… the effect of which was to cover the original video entirely with the retouched version. Once I had determined that it could be done, it was easy to put together a few test cases:
#video-clipper size | Compensating video width |
---|---|
100% | 100% |
50% | 200% |
25% | 400% |
Which meant that my script, derived from earlier mobile-ready version of the image before-and-after comparator, could be applied with just a few alterations:
function trackLocation(e) {
var rect = videoContainer.getBoundingClientRect(),
position = ((e.pageX - rect.left) / videoContainer.offsetWidth) * 100;
if (position <= 100) {
videoClipper.style.width = position+"%";
clippedVideo.style.width = ((100/position)*100)+"%";
clippedVideo.style.zIndex = 3;
}
}
var videoContainer = document.getElementById("video-compare-container"),
videoClipper = document.getElementById("video-clipper"),
clippedVideo = videoClipper.getElementsByTagName("video")[0];
videoContainer.addEventListener( "mousemove", trackLocation, false);
videoContainer.addEventListener("touchstart",trackLocation,false);
videoContainer.addEventListener("touchmove",trackLocation,false);
Surprisingly – considering that we have two videos stacked on top of each other, one being dynamically clipped and resized – the result worked very well on desktop browsers.
Mobile Issues
Getting the effect to work on mobile proved to be somewhat more challenging, due to the fact that video on mobile devices presents several obstacles:
- Video is not scaled responsively on iOS.
- To conserve bandwidth, video is not autoplayed on mobile devices.
The first issue is solved relatively easily, by using a variation on the techniques I have shown to make YouTube video responsive. The new, complete CSS for the example is below:
#video-compare-container {
display: inline-block;
line-height: 0;
position: relative;
width: 100%;
padding-top: 42.3%;
}
#video-compare-container > video {
width: 100%;
position: absolute;
top: 0;
height: 100%;
}
#video-clipper {
width: 50%;
position: absolute;
top: 0;
bottom: 0;
overflow: hidden;
}
#video-clipper video {
width: 200%;
position: absolute;
height: 100%;
}
The second problem was rather more difficult. iOS won’t autoplay video, for good and defensible reasons. With video controls absent, it is possible to create a button that will play a video: but only one at a time; iOS balked at playing two videos simultaneously.
In the end, I fell back to leaving the video poster images in place, allowing the user to scrub back and forth to compare the first frames of the original footage and its retouched version, autoplaying the videos only on devices that supported the feature. This works in iOS on the iPad, but the iPhone UI allows the user to click through and see the video(s) in fullscreen mode. That’s less than ideal, but could be addressed by using matchMedia
to remove the videos entirely at smaller screen sizes, leaving only the first frame images for comparison.
Futher improvements would use more JavaScript to synchronize the playback of both videos: right now, they start playing as soon as possible, occasionally causing one to lag behind the other.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/EIKzk