What is it, what's for?
Before|After is a comparison feature between two images. I originally developed this tool to allow my readers to be able to very quickly and with high efficiency, compare my photographies before and after the post-processing. This allows me to support beginners and amateurs in a logic of learning photography in an opened way. This habit is still uncommon, it is especially in contrast to nauseous methods so many people still adopt, suggesting — to the most novice and/or naive — that their photos are unedited, right from the camera, etc. A pseudo attempt at self-preservation, very ridiculous, but also human too…
The function is particularly simple to use: just place the mouse cursor over the image to be compared and the function is activated immediately, thus allowing, while you ride the cursor, to compare two different states.
Small but powerful
- Free.
- Easy tool, efficient and fun.
- Compare just anything you want.
- For personal & pro. projects
- Cross-platform.
- Tablets and Smartphones.
- Many options.
- Complete documentation.
- Customize each comparison.
- Adapt the code to your needs.
License
by Édouard Puginier is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. Permissions beyond the scope of this license may be available at http://tazintosh.com/en/contact/
Demos and ideas
Everything that can answer to the concept of Before|After fits this tools. Examples below against are only a minimal part of the feature potential.
It's just up to you!
- Before|After photo adjustments
- Before|After funny
- Before|After 3D Compositing
- Before|After Colorization
- Before|After Make-Up
- Before|After laboratory experiment
- Before|After culinary
- Before|After hairdressing
- Before|After cleaning-up
- etc.
Each example provided here has specifics settings to demonstrates the tool features. Check-out the code under each to discover them.
What's new on the last version?
Version 1.5.1 - 30/09/2014
- Added a CSS attribute to avoid a possible overflow of the handle.
Version 1.5 - 26/08/2014
- Touch events! The tool now works on tablets and smartphones.
- Option to display a handled to encourage manipulation.
- Option for the handle size.
- Option to display a slice line between the two elements to compare.
- Option to set the default position of the slice.
- Option for horizontal or vertical comparison.
- Option to keep the comparison in place even if the mouse or the finger leave the area.
- CSS Classes have been prefixed to avoid compatibility problem. You'll have to update your existing comparisons, I'm sorry about that, but it's for a good cause ;)
- Option to display or not labels “Before”, “After”.
- Option to customize labels.
- Option to keep labels always visible or only when comparing.
- Each option can be applyed independently on each comparison.
Version 1.0 - 25/04/2012
- Initial public release of Before|After comparison feature.
Three steps install
The tool is composed as follows: the HTML code basically constituted of the two images to compare, included in a container; a CSS stylesheet; the Javascript (jQuery) code to handle the user interaction.
#1 HTML
A two images comparison is built upon 4 lines of codes. It's possible to add as many comparison as needed on a page. By default, all of them are displayed with the default options set in the Javascript (lines 10 to 19). However, each comparison can be set independently with specifics options (see above examples).
src
property with your own image path.I recommend you to set the width of your comparisons. This can prevent rendering problems depending your stylesheets and website structure.
To do this, line 1, add style="max-width:
width of the comparison
px"
Custom options (for each comparison) are set line 1.
Write them like following data
-
option name
=
"value"
Global settings are set lines 10 to 19 of the Javascript.
Available options:
data-showhandle="true"
(default)
false
to hide the handle.data-handlesize="30"
(default)
Handle diameter in pixel.data-showslice="true"
(default)
false
to hide the separation slice between the two elements to compare.data-initialslicepos="20"
(default)
Initial position of the comparison (% of the width).
0
shows 100% of the “after” image,
60
shows 60% of “before” and 40% of “after”,
100
shows 100% of “before” image.data-horizontalslice="false"
(default)
true
for a top to bottom comparison.
data-keepinplace="true"
(default)
false
display 100% of the “after” image when the finger or cursor leaves the comparison area.data-showlabels="true"
(default)
false
hides labels.data-labelbefore="BEFORE"
(default)
“Before” image label.data-labelafter="AFTER"
(default)
“After” image label.data-alwaysshowlabels="false"
(default)
true
always shows labels, even if the finger or cursor leaves the comparison area.
<div class="_BA_comparisonArea" style="max-width:630px"> <img class="_BA_afterElement" src="pathToTheAfterPicture" alt=""> <img class="_BA_beforeElement" src="pathToTheBeforePicture" alt=""> </div>
<div class="_BA_comparisonArea" style="max-width:630px" data-showhandle="false" data-initialslicepos="50"> <img class="_BA_afterElement" src="pathToTheAfterPicture" alt=""> <img class="_BA_beforeElement" src="pathToTheBeforePicture" alt=""> </div>
#2 CSS
The stylesheet provides the look to the comparaison and also make them work the good way. It applies to all comparisons on screen. If you know about CSS, you can modify this style to your needs (specialy to adapt colors to your visual identity).
You may add the CSS to the <head>
of your website. A method is to copy/paste the following code on a file _BA_styles.css
you'll then call on the head like this: <link rel="stylesheet" href="pathToMyFile/_BA_styles.css">
.
background-color:
yellow;
value to red;
for the class ._BA_handle
will modify the handle color from yellow to red.._BA_comparisonArea { cursor: ew-resize; position: relative; overflow: hidden; } ._BA_comparisonArea.hasHorizontalSlice { cursor: ns-resize; } ._BA_afterElement, ._BA_beforeElement { display: block; margin-left: auto; margin-right: auto; left: 0; right: 0; top: 0; } ._BA_beforeElement { position: absolute !important; } ._BA_slice { position: absolute; width: 1px; height: 100%; top: 0; left: auto; background-color: rgba(0, 0, 0, 0.3); } ._BA_comparisonArea.hasHorizontalSlice ._BA_slice { width: 100%; height: 1px; top: auto; left: 0; } ._BA_handle { position: absolute; background-color: yellow; box-shadow: 0 0 2px rgba(0, 0, 0, 0.4); } ._BA_label { position: absolute; font-family: 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-weight: bold; font-size: 9px; line-height: 12px; letter-spacing: 1px; top: 48%; padding: 4px; border-radius: 4px; color: white; background-color: rgba(0, 0, 0, 0.5); } ._BA_comparisonArea.hasHorizontalSlice ._BA_label { margin-left: auto; margin-right: auto; } ._BA_label-left { left: 10px; } ._BA_comparisonArea.hasHorizontalSlice ._BA_label-left { top: auto; bottom: 10px; } ._BA_label-right { right: 10px; } ._BA_comparisonArea.hasHorizontalSlice ._BA_label-right { top: 10px; }
#3 Javascript
The script may be added into the <head>
of your website. A method is to copy/paste the following code on a file _BA_scripts.js
that you'll call on the head after the jQuery library call, like this: <script src="cheminVersLeFichier/_BA_scripts.js"></script>
.
If you call the function into your own script and want to re-execute it (ie. after a window resize, if your image size has changed), you can pass the
true
parameter.setupComparison(beforeElement, true);
/* ==================================================================================== */ /* Before|After • Comparison Feature v1.5.1 — © Édouard Puginier — https://tazintosh.com */ /* Under Creative Common license Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) */ /* ==================================================================================== */ function setupComparison(comparisonArea, reset){ jQuery(function($){ /* ========================= Defaults */ var showHandle = true, // false handleSize = 30, // Diameter in px showSlice = true, // false initialSlicePos = 20, // Percent horizontalSlice = false, // true for top to bottom comparison keepInPlace = true, // false. Will make “after” image 100% visible when leaving the comparison area showLabels = true, // false labelBefore = 'BEFORE', // Desired label for the before image labelAfter = 'AFTER', // Desired label for the after image alwaysShowLabels = false; // Will show labels even while not hover /* ========================= Init */ var pointer = '', posX = 0, posY = 0, slice = null, handle = null, labels = null, offset = '', beforeElement = $(comparisonArea).find('._BA_beforeElement'), elementWidth = $(beforeElement).width(), elementHeight = $(beforeElement).height(); if (reset){ $(comparisonArea).removeClass('hasOverlay'); $(comparisonArea).find('._BA_slice').remove(); $(comparisonArea).find('._BA_handle').remove(); $(comparisonArea).find('._BA_label').remove(); } /* ========================= Get values */ showHandle = ($(comparisonArea).attr('data-showhandle')) ? $(comparisonArea).data('showhandle') : showHandle; handleSize = ($(comparisonArea).attr('data-handlesize')) ? $(comparisonArea).data('handlesize') : handleSize; showSlice = ($(comparisonArea).attr('data-showslice')) ? $(comparisonArea).data('showslice') : showSlice; initialSlicePos = ($(comparisonArea).attr('data-initialslicepos')) ? $(comparisonArea).data('initialslicepos') : initialSlicePos; horizontalSlice = ($(comparisonArea).attr('data-horizontalslice')) ? $(comparisonArea).data('horizontalslice') : horizontalSlice; keepInPlace = ($(comparisonArea).attr('data-keepinplace')) ? $(comparisonArea).data('keepinplace') : keepInPlace; showLabels = ($(comparisonArea).attr('data-showlabels')) ? $(comparisonArea).data('showlabels') : showLabels; labelBefore = ($(comparisonArea).attr('data-labelbefore')) ? $(comparisonArea).data('labelbefore') : labelBefore; labelAfter = ($(comparisonArea).attr('data-labelafter')) ? $(comparisonArea).data('labelafter') : labelAfter; alwaysShowLabels = ($(comparisonArea).attr('data-alwaysshowlabels')) ? $(comparisonArea).data('alwaysshowlabels') : alwaysShowLabels; function getEvent(event){ return event.originalEvent.targetTouches ? event.originalEvent.targetTouches[0] : event; } /* ========================= Allows to append only once */ if (!$(comparisonArea).hasClass('hasOverlay')){ if (showSlice){ beforeElement.parent().append(''); slice = $(comparisonArea).find('._BA_slice'); } if (showHandle){ beforeElement.parent().append(''); handle = $(comparisonArea).find('._BA_handle'); } if (showLabels){ beforeElement.parent().append(''); labels = $(comparisonArea).find('._BA_label'); } } if (showSlice || showHandle || showLabels){ $(comparisonArea).addClass('hasOverlay'); } if (horizontalSlice){ $(comparisonArea).addClass('hasHorizontalSlice'); } /* ========================= Slice display */ if ((showSlice) && (slice !== null)){ if (initialSlicePos === 0){ slice.css('display', 'none'); } if (!horizontalSlice){ posX = elementWidth*initialSlicePos/100; slice.css('left', posX + 'px'); } else { posY = elementHeight*initialSlicePos/100; slice.css('top', posY + 'px'); } } /* ========================= Handle display */ if ((showHandle) && (handle !== null)){ handle.css({ 'width': handleSize + 'px', 'height': handleSize + 'px', 'border-radius': handleSize + 'px' }); if (!horizontalSlice){ posY = (elementHeight-handleSize)/2; handle.css({ 'margin-left': handleSize / -2 + 'px', 'top': posY + 'px', 'left': posX + 'px' }); } else { posX = (elementWidth-handleSize)/2; handle.css({ 'margin-top': handleSize / -2 + 'px', 'top': posY + 'px', 'left': posX + 'px' }); } } else { if (!horizontalSlice){ posX = elementWidth*initialSlicePos/100; } else { posY = elementHeight*initialSlicePos/100; } } /* ========================= Labels display */ if ((showLabels) && (labels !== null)){ $(comparisonArea).find('._BA_label-left').html(labelBefore); $(comparisonArea).find('._BA_label-right').html(labelAfter); if (!alwaysShowLabels) { labels.css('display', 'none'); } if (horizontalSlice && showLabels){ labels.each(function(){ $(this).css({ // Center labels horizontaly (other attributes are set in the stylesheet) 'width': $(this).outerWidth(), 'left': 0, 'right': 0 }); }); } } if (!horizontalSlice){ beforeElement.css('clip', 'rect(auto,' + posX + 'px , auto, auto)'); } else { beforeElement.css('clip', 'rect(' + posY + 'px, auto, auto, auto)'); } /* ========================= Comparison starts */ $(comparisonArea).on('mouseenter touchstart', function() { if (!keepInPlace) { if (showSlice){ slice.css('display', 'block'); } } }); /* ========================= Comparison is running */ $(comparisonArea).on('mousemove touchmove', function(event) { event.preventDefault(); pointer = getEvent(event); offset = $(this).offset(); posX = pointer.pageX - (offset.left); posY = pointer.pageY - (offset.top); if (!horizontalSlice){ beforeElement.css('clip', 'rect(auto,' + posX + 'px, auto, auto)'); } else { beforeElement.css('clip', 'rect(' + posY + 'px, auto, auto, auto)'); } if ((showSlice) && (slice !== null)){ if (!horizontalSlice){ slice.css('left', posX + 'px'); } else { slice.css('top', posY + 'px'); } } if ((showHandle) && (handle !== null)){ handle.css({ 'display': 'none', 'left': posX + 'px', 'top': posY + 'px' }); } if ((showLabels) && (labels !== null)){ labels.css('display', 'block'); } }); /* ========================= Comparison ends */ $(comparisonArea).on('mouseleave touchend touchcancel', function() { if (!keepInPlace) { beforeElement.css('clip', 'rect(auto, 0px, auto, auto)'); if (showSlice){ slice.css('display', 'none'); } } else { if (showHandle){ handle.css('display', 'block'); } } if ((showLabels) && (!alwaysShowLabels)){ labels.css('display', 'none'); } }); }); } jQuery(function($){ $(window).load(function(){ /* ========================= Detecting available comparisons */ $('._BA_comparisonArea').each(function(){ setupComparison(this); }); }); });
They are using it!
If you too, are using this tool, let me know and I'll update this list with your name, website and Twitter.
A good way to make your work known!
What else?
Use the form following or post a comment at the bottom of this article to share your ideas/needs. If you make changes to the code, thank you for sharing them by posting a comment explaining the work done, or by sending me an email using this form. You can even attach a file.
Many hours have been needed to develop this tool and present it here. Even if it's provided for free, if you think it gives a great service to your readers or customers, you can offer me littl'somethin'.
This symbolic coffee would be a true expression of your appreciation of this work.