Jquery Image Fade Cross Transition
Image rollovers were the staple JavaScript nugget of the 90s, and for a lot of JavaScript developers I know, one of the starting places their passion for JavaScript. Today, rollovers are a no-brainer - either in CSS or with the simplest of [removed]
$(function () { $('img.swap').hover(function () { this.src = 'images/sad.jpg'; }, function () { this.src = 'images/happy.jpg'; }); });
How to Approach the Problem
There are a few different ways which problem can be solved (and I’d love to hear alternative methods via the comments).
Here are the ways I’m going to go through:
- Two Image
- Single Image
- Pure CSS
The key to all of these techniques is how the rendered markup (i.e. what the browser finally sees) is arranged: all of which are very similar.
Essentially, the end image for the transition must sit absolute
ly in the same position as the starting image.
It’s also worth keeping in mind that the images we fade between should be the same size (height & width-wise).
Note: all three of these techniques have a caveat: styling the start or end image may cause the effect to break. I would recommend wrapping the image in a div
or span
and styling that element, as it will require less changes to the JavaScript. Either way: it is always best to test in the target browsers.
Two Image Technique
I should start by crediting Karl Swedberg who runs Learning jQuery. He solved Nathan’s transition problem using the following technique.
Karl’s method starts with the two images in the markup: both the start and end images. They are contained in a div
and the end image is contained in a further div
with absolute
positioning.
It is important to note that this technique works best for absolutely position images. Changing the div.fade
to position: relative
means the div
element remains as a block
element, and div
will stretch the with of it’s container element (defaulting to 100%).
HTML
<div class="fade"> <a href="/info.html"><img src="start.jpg" /></a> <div> <a href="/info.html"><img src="end.jpg" /></a> </div> </div>
CSS
Obviously if I had more than one fading image, I would use an ID or alternative class to position the top
and left
CSS properties.
.fade { position: absolute; top: 100px left: 100px } .fade div { position: absolute; top: 0; left: 0; display: none; }
jQuery
// when the DOM is ready: $(document).ready(function () { // find the div.fade elements and hook the hover event $('div.fade').hover(function() { // on hovering over, find the element we want to fade *up* var fade = $('> div', this); // if the element is currently being animated (to a fadeOut)... if (fade.is(':animated')) { // ...take it's current opacity back up to 1 fade.stop().fadeTo(250, 1); } else { // fade in quickly fade.fadeIn(250); } }, function () { // on hovering out, fade the element out var fade = $('> div', this); if (fade.is(':animated')) { fade.stop().fadeTo(3000, 0); } else { // fade away slowly fade.fadeOut(3000); } }); });
Single Image Technique
This takes the two image technique further. I like the idea that we should let the JavaScript add the sugar to the markup - in that we should really only want an image tag, and using some method to know what image we want to fade to.
This technique allows us to insert the image in the markup as we would if there were no transition effect, and the image can be inline, rather being positioned absolutely.
We are going to use the background-image
CSS property to specify the target image to fade to.
HTML
<img class="fade" src="images/who.jpg" style="background: url(images/who_ro.jpg);" />
CSS
Other than the inline background image - none is required. You can also apply the background-image
using classes if you like.
If we wanted to absolutely position the image, or float: right
for instance, the best way to do this (if we want to keep the transition), would be to wrap it in a div
and style that element.
jQuery
Using jQuery, we execute the following tasks:
- Wrap the image in a
span
- Insert a new image, whose source is the
background-image
of our start image - Position the new image so that sits directly behind the starting image
- Bind hover event to start the effect
// create our transition as a plugin $.fn.crossfade = function () { return this.each(function () { // cache the copy of jQuery(this) - the start image var $$ = $(this); // get the target from the backgroundImage + regexp var target = $$.css('backgroundImage').replace(/^url|[()]/g, '')); // nice long chain: wrap img element in span $$.wrap('<span style="position: relative;"></span>') // change selector to parent - i.e. newly created span .parent() // prepend a new image inside the span .prepend('<img>') // change the selector to the newly created image .find(':first-child') // set the image to the target .attr('src', target); // position the original image $$.css({ 'position' : 'absolute', 'left' : 0, // this.offsetTop aligns the image correctly inside the span 'top' : this.offsetTop }); // note: the above CSS change requires different handling for Opera and Safari, // see the full plugin for this. // similar effect as single image technique, except using .animate // which will handle the fading up from the right opacity for us $$.hover(function () { $$.stop().animate({ opacity: 0 }, 250); }, function () { $$.stop().animate({ opacity: 1 }, 3000); }); }); }; // Not only when the DOM is ready, but when the images have finished loading, // important, but subtle difference to $(document).ready(); $(window).bind('load', function () { // run the cross fade plugin against selector $('img.fade').crossfade(); });
Pure CSS Technique
If I’m honest, this final technique is a bit cheeky - but still valid. It uses CSS animations only (currently) available in Safari 3 (and WebKit).
However, this is a great example of how to the leverage the CSS using an iPhone (over using JavaScript).
The HTML is the same rendered HTML from the single image technique - but it requires zero JavaScript.
HTML
<span style="position: relative;"> <img src="images/who_ro.jpg" /> <img style="position: absolute; left: 0px;" src="images/who.jpg" class="fade" /> </span>
CSS
Although this is only supported in Safari 3, the roll over still works in Firefox (and could work in IE7 - though not IE6 because :hover
only works on anchors) - because it’s changing the image’s opacity on :hover
.
img.fade { opacity: 1; -webkit-transition: opacity 1s linear; } img.fade:hover { opacity: 0; }
You might also like
Tags
accordion accordion menu animation navigation animation navigation menu carousel checkbox inputs css3 css3 menu css3 navigation date picker dialog drag drop drop down menu drop down navigation menu elastic navigation form form validation gallery glide navigation horizontal navigation menu hover effect image gallery image hover image lightbox image scroller image slideshow multi-level navigation menus rating select dependent select list slide image slider menu stylish form table tabs text effect text scroller tooltips tree menu vertical navigation menu