Posted: April 1st, 2007 | Author: Panagiotis Karageorgakis | Filed under: jQuery | 16 Comments »
jQuery is a very popular JavaScript library among web developers, gaining more and more fans as it evolves. It’s fast, lightweight and does many things while being unobtrusive, meaning that no code has to be incorporated in an (X)HTML document’s body. This way, the designer can write the code, and then go to the document’s head and add a few lines of code to do some fancy stuff with the document. Between the several built-in effects are the popular fade-in and fade-out effects that, due to the chainablity of jQuery can be used sequentially, for a fade-in-then-fade-out effect.
Chainability, is the ability to “chain” different methods on an object, like this:
Chainability in all its glory
$("#foo").show().hide();
which will just show and then hide the element with the id “foo”.
Fade-in-fade-out
Using the concept of chainability, we can achieve a fade-in-fade-out effect easily:
A simple fade-in-fade-out
$(document).ready(function() {
$("#foo").fadeIn(2000).fadeOut(2000);
});
The above fragment of codefades in the #foo element with a duration of 2 seconds (2000 milliseconds — the argument is in ms), then it fades out the element. The duration of the fade-out effect is another 2 seconds. But what happens if we wanted to have a delay, between the fading-in and fading-out of the element? Say, for example, that we want to fade in the element, then keep it that way for 5 seconds, and then fade it out again.
Intuitively, the “I-dont-read-documentation-but-guess-my-way-around” kind of developer would try to chain a delay effect, like this:
We wish we could do this…
$(document).ready(function() {
$("#foo").fadeIn(2000).delay(5000).fadeOut(2000);
});
However, this won’t work, simply because there’s not a delay() function. The outcome would be for the element to fade in, and then do just nothing, since the script encounters a function that is non-existent and just stops there. So how can we achieve that?
The trick
Let’s think of what happens during the fadeIn() function: the JavaScript alters the opacity property of an element, from zero to 1, which corresponds to a transition between 0% and 100% of opacity. The fadeOut() function does the reverse: changes the opacity property gradually from 1 to zero. There’s a third function named fadeTo(), which fades the given element to a specific opacity that is passed to it as an argument. For example, the following line of code would make the #foo element go from total invisibility to 50% opacity (the effect will last 3 seconds):
Fade from completely opaque to 50% visible
$("#foo").fadeTo(3000, 0.5);
The trick is to simulate the delay by applying a fade-in (or fade-out) effect that does not change the opacity of an element, but rather spends it’s time doing nothing. The concept is as follows:
- Fade-in the element from 0 opacity to 1, for 2 seconds
- Fade-in the element again from 1 opacity to 1, for 5 seconds
- Fade-out the element from 1 opacity to 0, for 2 seconds
This way, we just insert a transition that last 5 seconds but does not change the opacity of the element, since the target opacity has the same value as in the current condition. The code would just be as simple as this:
The trick is to use the fadeTo() effect!
$(document).ready(function() {
$("#foo").fadeIn(2000).fadeTo(5000, 1).fadeOut(2000);
});
As Karl Swedberg correctly stated in a comment below, the same effect can be achieved by using the animate() effect, i.e.: .animate({opacity: 1.0}, 3000)
Delaying an effect before it begins
Now, let’s alter the desired effect a little bit. Let’s say that, our foo element is rather shy; it doesn’t want to appear just as the page loads, but would rather give the reader some time to settle in, before it intrudes in the page. A few seconds would be enough for our element to feel comfortably, so we want to give it 3 seconds time until it appears. How do we do this? Intuitively we would expect something like the following code to work:
(This is not the right way to code what we want)
$(document).ready(function() {
$("#foo").fadeTo(3000, 0).fadeIn(2000)
.fadeTo(5000, 1).fadeOut(2000);
});
Previewing this in our browser, we see that it’s not what we expected. Foo shows momentarily, then disappears, waits, and then begin to fade in. But why did foo make a quick appearance and then disappear, before it does it’s part? Maybe it wanted to peek and see who the viewer is, but I bet there’s a better explanation, and there is one: the original opacity of it was 1, so fading to 0 creates a transition (a short one) to the target opacity.
[Edit: The following part of this section of the document has been updated to add support for internet Explorer 7]
Here’s a way to achieve this effect. This method has been tested in Safari and Firefox 2 for the Mac, as well as Firefox 2 and IE 7 for Windows. The trick here is to initially hide the element, not by altering it’s opacity, but rather by taking it out of the document flow. This can be done the same way designers choose to hide accessibility text, by creating a class like the following:
Create a .hidden class
.hidden {
position: absolute;
top: -10000px;
}
Then all we have to do is this: apply the class to our element, create a fadeTo transition that takes the desired time, remove the class from the element then go on with our normal effects. To make a long story short, in order to have all the aforementioned browsers support this, we must keep in mind two things:
- Use fadeTo() effects to substitute fadeIn() and fadeOut() effects (e.g. fadeTo(”normal”, 1) is the same as fadeIn(”normal”) )
- Use the remove class attribute as the delaying transition’s callback function
In a nutshell, if we want to have an element delay 3 seconds, fade in, wait another 3 seconds and then fade out, here’s the proper code:
The right way to do it
$("#foo").addClass("hidden").fadeTo(3000, 0, function() {
$(this).removeClass("hidden")
}).fadeTo("slow", 1).fadeTo(3000, 1).fadeTo("slow", 0);
Now, if anyone’s kind enough to try this with Internet Explorer 6 or below, plase let us know by leaving a comment.
You can see a real world live example of this behaviour in a simple intro page (that has inspired me to write this article). Three seconds after the page loads, an image containing some text appears above the graphic, waits for 2 secs and fades out.