Saturday, July 20, 2013

Build a Before/After Widget Using CSS and JS

On a recent assignment of mine I had to develop a widget that allows the user to preview effects applied on a photo using a split screen. It is possible to modify how much you can see of either image simply by moving cursor or finger over the viewport. The fiddle below illustrates the idea:

As you can see, the idea is quite simple. Our markup looks like this when simplified to Jade syntax:

  • div#container
    • div.crop
      • img.overlay

The CSS portion is really minimal as well. We need to work around a certain limitation by setting vertical-align but otherwise it's nice and clear.

.crop {
    overflow: hidden;
    width: 50%;

.photo {
    vertical-align: bottom;

We simply make sure our cropping container acts as a viewport by setting overflow property to hidden and show only half of it by default. Adjust that to your liking. Without the latter hack the photo would be about four pixels off. Don't ask why as I didn't write the spec.

Finally there is a little bit of JavaScript to tie it all together. As I felt lazy I wrote it using jQuery. It gets to the point, though.


function main() {
    var $e = $('#container');
    var $photo = $('.photo', $e);
    var $crop = $('.crop', $e);

    $e.css('width', $photo.width());    
    $crop.css('margin-top', -$photo.height());
    $e.on('mousemove touchmove', function(e) {
        $crop.css('width', e.pageX - this.offsetLeft);

As you can see the trick is simply to position the crop container on top of the original image by using a negative margin. The container width is set to photo width so that the initial relative width given to the cropped functions as you might expect it to.

In case you wish to avoid that negative margin, you may get away with absolute positioning. I don't see any advantages in that approaches, though, except perhaps it is a bit less negative?


This little technique could be a starting point for some interesting development. Given it's based partly on CSS it is very easy to style. You can apply effects such as opacity. On the JS side you could animate it. You could even attach text to the elements and have some sort of captions there.

It would be possible to develop an entire slideshow or a carousel of top of the idea. I hope you have fun with it! Let me know if you get something cool done with the idea.