Create an Attractive Before and After Photo Effect with jQuery

Create an Attractive Before and After Photo Effect with jQuery


Create an Attractive Before and After Photo Effect with jQuery

Introduction

13 Jan 2011, Australia suffered a catastrophic flood disaster, almost 75% of Queensland was affected. Inland Tsunami in Toowoomba, evacuation of Brisbane city, it was a total chaos in the entire state. Sudden flood which lead to torrential and ferocious flood destroyed homes and killed many. It will take 2 years to recover. If you wish to donate, please visit Queensland Government State Website.

The reason I bought it up because I got this inspiration from this website - Queensland Floods - Before After.

Well, it is saddening to see all the damages the flood did. In the other hand, I also notice the way it presents the before and after photos. It's just so intuitive and simple. So, I have decided to build something similar but with a few of enhancements. I'm going to show you how to build it and how to convert it to plugins. Tested on IE6, 7, 8, Firefox, Chrome and Safari. 

You may want to check out the demo now:

HTML

I keep the HTML really simple, just a div with 2 images in it. Things you need to know:

  • value in ALT attribute will be used as caption
  • width and height of the first image will be used for calculation, therefore, it's mandatory to have it defined

This is what you need to use it:

<div class="beforeafter">
	<img src="image-1.jpg" alt="Before" width="500" height="280">
        <img src="image-2.jpg" alt="After" width="500" height="280">																																							
</div>

However, the content in the div will be totally revamped once it's processed by javascript. This is the real structure:

<div class="beforeafter">
	<div class="ba-mask"></div>
	<div class="ba-bg"></div>
	<div class="ba-caption"></div>
	<img src="image-1.jpg" alt="Before" width="500" height="280">
	<img src="image-2.jpg" alt="After" width="500" height="280">		
</div>
<div class="beforeafter">
	<img src="image-1.jpg" alt="Before" width="500" height="280">
        <img src="image-2.jpg" alt="After" width="500" height="280">																																							
</div>

CSS

CSS isn't that complicated as well. I have illustrated how this script going to work which will make it easy to understand

Queness before and after jQuery Plugin Tutorial
#container {width:500px; margin:0 auto;}
		
/* width and height for the block */
.beforeafter {width:500px; height:280px;}		
		
		
/* The following is the mandatory styling for the plugins */
	
.ba-mask {	/* first image */	
	position:absolute; 
	top:0; 
	left:0; 
	z-index:100; 
	border-right:4px solid #000; 
	overflow:hidden; 
	box-shadow: 3px 5px 5px rgba(0, 0, 0, 0.6);
	box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.6); 
	-webkit-box-shadow: 5px 5px 7px rgba(0, 0, 0, 0.6);  
	-moz-box-shadow: 5px 0 7px rgba(0, 0, 0, 0.6);
}

.ba-bg {	/* second image */
	position:absolute; 
	top:0; 
	left:0; 
	z-index:0;
}

.ba-caption {	/* caption	*/
			
	/* mandatory */
	position:absolute; 
	bottom:10px; 
	left:10px; 
	z-index:120;	
			 
	/* customizable styling */
	background:#000; 
	color:#fff; 
	text-align:center;
	padding:5px; 
	font-size:12px; 
	font-family:arial; 
	filter:alpha(opacity=80);-moz-opacity:0.8;-khtml-opacity: 0.8;opacity: 0.8; 
	-webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; 			
}

Javascript

Alright, some intensive stuff going on over here. The length of the script is pretty long, it's because I'm trying to make this script as flexible as possible and also make the HTML and CSS as simple as possible. You see, once we have the flexibility and simplicity lead to lengthly and complicated code.

I have written a comment to walk you through the whole javascript.

$(document).ready(function() {
	
	// Some options for customization
	var leftgap = 10;		/* gap on the left */
	var rightgap = 10;		/* gap on the right */
	var defaultgap = 50;	/* the intro gap */
	var caption = true;		/* toggle caption */
	var reveal = 0.5;		/* define 0 - 1 far does it goes to reveal the second caption */
		
	// find each of the .beforeafter
	$('.beforeafter').each(function () {
		
		// set current selected item to variable
		var i = $(this);			
		// get the source of the first image and second image using eq(index)
		var img_mask = i.children('img:eq(0)').attr('src');
		var img_bg = i.children('img:eq(1)').attr('src');
			
		// get the caption for the first image as default caption
		var img_cap_one = i.children('img:eq(0)').attr('alt');
			
		// get the dimension of the first image, assuming second image has the same dimension
		var width = i.children('img:eq(0)').width();
		var height = i.children('img:eq(0)').height();
			
		// hide the images, not removing it because we will need it later
		i.find('img').hide();		
			
		// set some css attribute to current item for graceful degradation if javascript support is off
		i.css({'overflow': 'hidden', 'position': 'relative'});
			
		// append additional html element
		i.append('</pre><div class="ba-mask"></div><pre class="js">');
		i.append('</pre><div class="ba-bg"></div><pre class="js">');			
		i.append('</pre><div class="ba-caption">' + img_cap_one + '</div><pre class="js">');						
			
		// set the dimension of appended html element
		i.children('.ba-mask, .ba-bg').width(width);
		i.children('.ba-mask, .ba-bg').height(height);
			
		// set the images as background for ba-mask and ba-bg
		i.children('.ba-mask').css('backgroundImage','url(' + img_mask + ')');
		i.children('.ba-bg').css('backgroundImage','url(' + img_bg + ')');				

		// animate to reveal the background image
		i.children('.ba-mask').animate({'width':width - defaultgap}, 1000);		

		// if caption is true, then display it, otherwise, hide it
		if (caption) i.children('.caption').show();
		else i.children('.ba-caption').hide();
			
	}).mousemove(function (e) {

		// set current selected item to variable
		var i = $(this);
			
		// get the position of the image
		pos_img = i.offset()['left'];
			
		// get the position of the mouse pointer
		pos_mouse = e.pageX;		
			
		// calculate the difference between the image and cursor
		// the difference will the width of the mask image
		new_width = pos_mouse - pos_img;
		img_width = i.width();
			
		// get the captions for first and second images
		img_cap_one = i.children('img:eq(0)').attr('alt');
		img_cap_two = i.children('img:eq(1)').attr('alt');
			
		/*
		// for debugging purposes
		$('#debug').html("X Axis : " + e.pageX + " | Y Axis " + e.pageY);
		$('#debug2').html(i.position()['left']);
		$('#debug3').html(new_width);
		*/
			
		// make sure it reveal the image and left some gaps on left and right
		// it depends on the value of leftgap and rightgap
		if (new_width &gt; leftgap &amp;&amp; new_width &lt; (img_width - rightgap)) {			
			i.children('.ba-mask').width(new_width);
		}	

		// toggle between captions.
		// it uses the reveal variable to calculate
		// eg, display caption two once the image is 50% (0.5) revealed.
		if (new_width &lt; (img_width * reveal)) {			
			i.children('.ba-caption').html(img_cap_two);
		} else {
			i.children('.ba-caption').html(img_cap_one);			
		}	 								
					
	});
	
 });
 

Convert to Plugin

First of all, what we need to know is the structure of a plugin. I shared about this long time ago, so if you want to know more about it, visit this post - A Really Simple jQuery Plugin Tutorial. Over here I will just paste the structure we going to use in this tutorial:

//You need an anonymous function to wrap around your function to avoid conflict
(function($){
 
    //Attach this new method to jQuery
    $.fn.extend({
         
        //This is where you write your plugin's name
        pluginname: function() {
 
            //Iterate over the current set of matched elements
            return this.each(function() {
             
                //code to be inserted here
             
            });
        }
    });
     
//pass jQuery to the function,
//So that we will able to use any valid Javascript variable name
//to replace "$" SIGN. But, we'll stick to $ (I like dollar sign :) )      
})(jQuery);

Alright, the next thing we need to do, mix the plugin stucture with the before after script, and this is the final result:

(function($){
   $.fn.extend({
		//plugin name - qbeforeafter
		qbeforeafter: function(options) {
 
			var defaults = {
				defaultgap: 50,            
				leftgap: 10,
				rightgap: 10,
				caption: false,
				reveal: 0.5
			};
             
			var options = $.extend(defaults, options);
         
			return this.each(function() {

            var o = options;
            var i = $(this);
			var img_mask = i.children('img:eq(0)').attr('src');
			var img_bg = i.children('img:eq(1)').attr('src');
			var img_cap_one = i.children('img:eq(0)').attr('alt');
			
			var width = i.children('img:eq(0)').width();
			var height = i.children('img:eq(0)').height();
				
			i.children('img').hide();		
				
			i.css({'overflow': 'hidden', 'position': 'relative'});
			i.append('</pre><div class="ba-mask"></div><pre class="js">');
			i.append('</pre><div class="ba-bg"></div><pre class="js">');			
			i.append('</pre><div class="ba-caption">' + img_cap_one + '</div><pre class="js">');
				
			i.children('.ba-mask, .ba-bg').width(width);
			i.children('.ba-mask, .ba-bg').height(height);
			i.children('.ba-mask').animate({'width':width - o.defaultgap}, 1000);
			
			i.children('.ba-mask').css('backgroundImage','url(' + img_mask + ')');
			i.children('.ba-bg').css('backgroundImage','url(' + img_bg + ')');	

			if (o.caption) i.children('.ba-caption').show();

            }).mousemove(function (e) {

				var o = options;
				var i = $(this);
				
				pos_img = i.offset()['left'];
				pos_mouse = e.pageX;		
				new_width = pos_mouse - pos_img;
				img_width = i.width();
				img_cap_one = i.children('img:eq(0)').attr('alt');
				img_cap_two = i.children('img:eq(1)').attr('alt');				

				if (new_width &gt; o.leftgap &amp;&amp; new_width &lt; (img_width - o.rightgap)) {			
					i.children('.ba-mask').width(new_width);
				}
				
				if (new_width &lt; (img_width * o.reveal)) {			
					i.children('.ba-caption').html(img_cap_two);
				} else {
					i.children('.ba-caption').html(img_cap_one);			
				}					
			
			});
        }
   });
})(jQuery);	

If we compared it to the non-plugin script, the major difference is how we convert the customizable setting (defaultgap, leftgap, rightgap, caption and reveal) to plugins. That's it, pretty straight forward, just copy and paste and slight modification

How to use Queness' beforeafter plugin

The usage is really simple, this is how you call the plugin:

	
$(function () {
	$('.large').qbeforeafter({defaultgap:50, leftgap:0, rightgap:10, caption: true, reveal: 0.5});
	$('.small').qbeforeafter({defaultgap:20, leftgap:5, rightgap:10, caption: false});
});

Finally...

That's it, a tutorial after a long time. I hope you guys will like it. If you have any questions, suggestion or comment, drop me a message below. Also, help me to spread this post :) Thanks.

Author: Kevin Liew

Kevin Liew is a web designer and developer and keen on contributing to the web development industry. He loves frontend development and absolutely amazed by jQuery. Feel free to say hi to me, or follow @quenesswebblog on twitter.

Share the love

52 comments

RSturim
Tue, 25th January 2011
Kevin,
Nice work! This is a well written, easy to follow article that offers a clever way to combine css and jquery into an interesting UX. It definitely gets me inspired to think about using this technique for patterns I may encounter in the future. Thanks for taking the time to craft a nice article.
-Rich Reply
Mark
Fri, 28th January 2011
Kevin,
Really impressive. I work in flood related work in the UK and wanted to know if there were any licencing restrictions to using your script, other than the GPL licencing related to Jquery?
Thanks,
Mark Reply
Kevin Liew Admin
Sat, 5th February 2011
Yes, you can use it :) Reply
Luz Elena
Tue, 1st February 2011
very good tutorial, thank you very much, salutations from Barcelona.
Reply
Ayaz Malik
Tue, 8th February 2011
Very well done love the final results ! Reply
csshunt
Wed, 16th February 2011
nice effect going to use somewhere soon Reply
Alin Oancea
Sat, 19th February 2011
Nice work! Reply
Andrew
Wed, 23rd February 2011
Wonderful idea & implementation!
I ran into a problem where the mask did not properly slide across the image. I found that if any of the container elements of the target class (#container, for example) is positioned relative, then it will not work quite right. I changed Line 48 above to use offset() instead of position() and now it works perfectly.
Thanks again for such an incredible plugin! Reply
Kevin Admin
Tue, 15th March 2011
Thanks! :) Reply
Sus
Sun, 21st August 2011
OMG I had been trying for a whole day to implement this in Joomla and always run into that mask problem, until I read your comment regarding using offset() instead of position() it finally worked! XD

Thank you so much Kevin for this amazing Jquery and Andrew for your lifesaving tip. Reply
Kevin Liew Admin
Sun, 21st August 2011
Sorry for that. I have updated the post. Reply
sam
Sun, 20th March 2011
Hi,
Thanks for the tuto,
Nevertheless, i would like to trigger the intro gap after something has been clicked or a div toggle.

Is that possible ? Can you please explain me how to do it.

I'm not literate with javascript and your help would be welcome.

Thanks in advance,
Best regards,
Sam

Reply
eika
Fri, 29th April 2011
awesome ! Reply
BenStern
Sun, 15th May 2011
Or you could just use the awesome before/after plugin at http://www.catchmyfame.com/2009/06/25/jquery-beforeafter-plugin/ Reply
William
Sat, 7th January 2012
Yes you can use CatchMyFrame but be CAREFULL you dont use it for anything commercial orientated as the author will try and charge you $!! for it cause ONLY for that plugin of his other 5 is here a hidden commercial clause if you have not checked into the script. THe restrictive Creative Commons clause is use be advertised NO WHERE on the site.

And as a "PLUGIN" why would one want to check the code............just plug it in ;-)

BE WARNED! His site should be CAUGHT YOU IF I CAN lol Reply
Tutorial Lounge
Fri, 3rd June 2011
excellent writing.. Reply
Jan
Mon, 12th September 2011
Hello.

Thanks for that great tutorial!

But i see one requirement for that effect: That the two pictures are as equal as possible, same point of view, same picture angle.

How to do that the best way? Is there any software which can help, or do you have to accomplish that in the moment when you take the "after"-Picture?

Jan Reply
Kevin Liew Admin
Mon, 12th September 2011
Hi Jan, that's the whole point of before and after effect isn't it? :) To see the changes of two photos from the same perspective. Well, it depends how you use it. You can use it to show the retouch effect of two photos. To achieve the best effect, yes you do need two pictures as equal as possible in the point of view and angle. Reply
Morten
Mon, 12th September 2011
Great work! Just what I was looking for! Reply
Morten
Thu, 15th September 2011
being a prototype.js user - I took your javascript and rewrote it to using protype - hope you don't mind. Still some work pending, but it works... it can be found at http://sickel.net/blogg/?p=1091 Reply
Kevin Liew Admin
Thu, 15th September 2011
Haha Morten, that's awesome! Prototype is the first javascript framework i learn! But I didn't dig deep enough. Good work. Reply
Mahendra
Tue, 4th October 2011
Thanks Kevin. Gr8 plugin Reply
Esther
Sun, 18th December 2011
This plugin is perfect for my client who wants to show "before" and "after" photos of his hair extensions models. However, I'm having trouble integrating this into a slideshow (like Cycle or Awkward), and was wondering if this is possible. Reply
Kevin Liew Admin
Tue, 20th December 2011
Hi Esther, I haven't tried that before but it seems to be a pretty complicated solution you got there. Reply
dr amir
Sat, 14th January 2012
first of all ..really great work ..the result is outstanding ..i've tried the catchmy script and although the bar is a bit fancier ..the scripting it self has nothing to compare to yours ..neat and effective .
i'm including it to a dental gallery , it will be awesome ..therefore and since i'm just a dentist with tiny skills in webdesign i would like to ask u just two tiny questions if i may:
1 is is possible to include a shadow or frame effect (pure css and html) on the pics without affecting the code .
2 is is possible to include the div in a webpage already build with another css ? or it would be easier to put the whole presentation in a popup if i can center the effet so it comes in the exact middle of the popup window ?
sorry for taking so long of your reading time ..it's just that i'm impressed :)

NB: u own me a free teeth cleaning if u even come to tunisia ;) Reply
Kevin Liew Admin
Sun, 15th January 2012
Hi Dr Amir, thanks for your kind words :)
1. it's possible, for border or shadow, you need to do this to this css class:

.beforeafter {
border:5px solid #666;
box-shadow:0 0 5px rgba(0,0,0,0.8);
}

2. you can mix this script with other html elements, it shouldn't conflict with the layout. Not so sure about popup, you might get something like fancybox then display this before and after script in an iframe. Reply
Ina
Mon, 20th February 2012
Exactly what I was looking for......great job!
Best regards,
Athens, Greece Reply
Mirco Brandes
Thu, 29th March 2012
Hello Kevin,
i try to use your script, but i have a big problem.
If i load the site the first time, the effekt is not visible / does not work.
If i refresh / reload the site everything ist okay.

Do you have an idea, how i can solve this problem.

If you need a link or something else please send me a message.

Thanks
Mirco
Reply
Josh
Fri, 20th April 2012
Mirco,

I'm having the same problem with the before/after only working on a second load of each page. Did you ever figure this out? Would love to know what's going on. Thanks. Reply
June
Fri, 30th March 2012
Hi
Is there an "easy" to change the code, that you don't have to drag from left to right, but from top to bottom?
Regards
J Reply
Kevin Liew Admin
Tue, 17th April 2012
hmm, top to bottom will take some time to fiddling around.. I made a quick one, behave a lil different.

http://www.queness.com/resources/html/beforeafter/index_top.html

Reply
Levi
Tue, 10th April 2012
This is really awesome, good work. Is there any way I could have it in some sort of carousel? So I could click next and go to another before and after picture?

Thanks! Reply
Kevin Liew Admin
Tue, 17th April 2012
hmm, tough request but you can try to put this script inside a carousel.... i doubt it will work though :p Reply
marti
Sun, 13th May 2012
Hey! Is that plugin under any license?
Thanks! Reply
Kevin Liew Admin
Wed, 13th June 2012
open source, you can use it and mod it. Reply
MarkL
Thu, 28th June 2012
Hi there. Great plugin. One suggestion: make it "responsive". Right now removing width/height breaks the code. I'm trying to integrate it with my design based on Twitter bootstrap and resizing the window browser just messes things up before of the hardcoded width/height.

Cheers. Reply
uzi
Wed, 31st July 2013
Yeah, this is real problem. I need this plugin but it have to work responsive Reply
Regi
Thu, 25th September 2014
Not perfect, but a solution for the responsive need is to use different sizes of this code for different situations, such as: small screen, desktop screen, touch screen. This way, it will not perfect fulfill all screens, but it can match some standards screen sizes in the market. At www.csstemplateheaven.com I found in the past a free template called css creative-studios template that has this screens sizes solution code. Reply
Flobs
Thu, 20th September 2012
Hi, I love the nice effect of the before and after photo but I was wondering if it also works on blogger? I tried to use it but I failed all the time. I'm quite a novide in programming stuff. Thank you for the awesome tutorial and sharing your work! Reply
Agrest123
Thu, 11th October 2012
Hi.
Awsome plugin. I do a page about a medieval town. I need implement this plugin in my homepage buid on a joomla 1.5. I read a tutorial and I don't know how could I this function on my page. Who wants explain me how can I do this? This plugin allows me show an old and present pictures on my page.
Sorry for my english. I'm from Poland
Thanks Reply
Maged
Wed, 19th December 2012
as mentioned in my previous post i usually use Flash, so i really miss the % size feature ..is there any chance that this script makes the photos dynamic i.e. set pictures size as a % of screen size width and height ?? as the constant Size interfere somewhat with a full dynamic sized website . Reply
Kevin Liew Admin
Thu, 20th December 2012
I'm guessing you're talking about responsive. Unfortunately, it can't do it. Reply
cugreen
Tue, 26th February 2013
Nice plugin. Thanks. I noticed I got image flickering if triggering mousemove before the initial animation finished.

I found putting a stop in fixed the issue. Like this.

i.children('.ba-mask').stop().width(new_width);
              Reply
serge
Sun, 10th March 2013
Hi,

How do i install the plugin on my word-press ? when i install it it says :The package could not be installed. No valid plugins were found.

Plugin install failed. Reply
Mimi
Wed, 10th April 2013
Can this be used on blogger?
And I'm not sure if I am doing this right.
I just copy and paste the code where I want it, right?
Or am I missing something? I have no clue 3:. Reply
Jimmy
Mon, 29th April 2013
I'd like to use this on my squaredspace page, but am lost as to how to customize it to my own images. When I'm editing a squaredspace gallery, there's a feature where I can input CSS, but I'm a complete imbecile with this stuff. I don't even know if squaredspace is even compatible with any of the code listed! Does anyone have any insight? Thanks! Reply
Kasia
Fri, 3rd May 2013
hello Kevin
this is exacely what I was looking for my retouching work :)

I builed my webside with 4ormat do You think I can instal Your plugin there??
or in some blogs like blogger and then just link it to my webside

i would be really grateful for Your comment

Kasia Reply
Master
Thu, 21st November 2013
whoeta Reply
Weber
Sun, 3rd August 2014
Please tell me why this plugin is not loading properly (images are sometimes loading, sometimes not loading) on Google Chrome and is loading perfect on Internet Explorer.... I'm using it in Joomla.. Reply
Weber
Sun, 3rd August 2014
Please tell me why this plugin is not loading properly (images are sometimes loading, sometimes not loading) on Google Chrome and is loading perfect on Internet Explorer.... I'm using it in Joomla.. Reply
Weber
Sun, 3rd August 2014
Please tell me why this plugin is not loading properly (images are sometimes loading, sometimes not loading) on Google Chrome and is loading perfect on Internet Explorer.... I'm using it in Joomla.. Reply
DaddySlap
Mon, 29th September 2014
hi! When I testing this plugin in Wordpress, is don't work in the Google Chrome. I think that it's problem of cache images. Help me plese. Reply

Leave a Comment

Please keep in mind that comments are moderated and rel="nofollow" is in use. You can use [code][/code] if you want to write codes. Don't spam us :) Thanks!

Advertisement