jQuery-Based Popout Ad: Part 2

Published September 16, 2008 by CSS Newbies.

Note: Part 1 of this series is available here. Be sure to read it first, or what comes here won’t make a lot of sense. :)

Part 2 of our series is going to build on what we accomplished last week. Namely, we’re going to take the ad we built last week and animate it, as well as provide the user with a means to open and close the ad. We’ll be using jQuery for most of what we do, so you’ll need to include the jQuery library script at the top of your document for this to work (see the source of the example page to see how this is done).

Before we get started on our JavaScript, however, we’ll need to make one tiny addendum to our CSS from last week:

#popout #adbox {
	margin-left: -300px;
}

This bit of CSS moves our ad box (the bit we hope to animate) 300 pixels to the left of where it sits normally. And because our ad is 300 pixels wide (convenient, no?) this effectively hides the ad off the side of the screen. This way, our ad is hidden by default, and we can use jQuery to slide it back onto the screen.

Now let’s get started with the jQuery. We’ll wrap everything we write today in a “document ready” function, which looks like this:

$(document).ready(function() {
});

This prevents everything we put inside from firing until the document has finished loading, which is a good thing for us: we don’t want our ad to start moving until it’s all loaded!

Set Some Variables

We’ll start by defining a few variables that we’ll use throughout the script:

var popOut = "#popout";
var adBox = "#adbox"; 
var adWidth = $(adBox).width() + $("#cap").width();

The first variable, popOut, contains the CSS ID of the overall popout container that we built last week. popOut contains the ad and the ad’s cap both. The second variable (adBox) is the ID of just the animated bit of the ad. And finally, adWidth is a custom-built variable which gives us the total width of the area our ad takes up (the width of the ad plus the width of the cap). This variable will come in handy when we start animating our ad, to let us know how much space we have to work with.

The Animation Functions

Now that we’ve defined our primary variables, let’s delve into the actual animation of the ad. I’ve broken both parts of our animations (sliding in to the page and sliding back out again) into two functions. The opening function looks like this:

function openAd() {
	$(popOut).width(adWidth+"px");
	$(adBox).animate({marginLeft: "0"},1200);
}

This tiny little function is doing a surprising amount of work (which is really the power of jQuery). The first line simply sets the width of the popout container to be the width of the ad plus the cap – making sure we have enough room to do our animation. This may seem redundant, but it’ll make more sense later.

The second line of our function is the real workhorse. Here, we’re using jQuery to build a custom animation, which we’re attaching to our adBox variable. We’re telling jQuery to set a left margin of zero on the adBox (to move it back to its “real” position, in other words). But instead of doing it all at once, we’re telling jQuery to slowly make the change over the course of 1200 milliseconds (or 1.2 seconds, if you prefer). Pretty powerful stuff for a single line of code, no?

And now that we’ve built the function to open our ad, we can build the function to close it back up again:

function closeAd() {
	$(adBox).animate({marginLeft: "-"+adWidth+"px"},1200,"linear",
		function(){ $(popOut).width($(".cap").width() + "px"); }
	);
}

This function is obviously a little more complicated, although it wouldn’t have to be if it weren’t for a but in Internet Explorer 6.

The first bit looks somewhat familiar, I hope. We’re setting another animation here, this time setting the left margin of the ad to be the negative of the width of the ad space, effectively hiding it off the side of the screen. And we’re doing it over the same 1.2 seconds as our last animation (though you can tweak these numbers to your heart’s content).

After that, things get a little more complicated. The next bit, “linear,” simply tells the animation function to maintain the same speed throughout the animation – not to slow down at the beginning or end.

And when the animation is finished, we’re firing off yet another function. This function sets the width of the popout area to be only as wide as the cap, since that’s the only part of the ad that is visible (hence why we have to set a width at the beginning of our openAd function).

This is because of a bug in Internet Explorer 6 that prevents the user from “clicking through” an empty div. What that means is, if the user tried to close your ad and then click on anything that had been previously hidden by the ad – a link in your sidebar, for example – they wouldn’t be able to click. Even though the ad is gone, IE6 would assume you were reserving the space for some greater purpose. So to get around this, we grow and shrink the popout space as necessary.

Create Click Events

Now that we’ve created our animation functions, we can attach them quickly and easily to the anchors we built last week for such a purpose. As you’ll recall, we included a “close” button in the corner of the ad – clicking this should obviously close the ad. And if someone ever wanted to see the ad again (we should be so lucky!), clicking the cap will bring it right back out.

$("#open").click(function() {
	openAd();
	return false; 
});
$("#close").click(function() {
	closeAd();
	return false;
});

These functions are fairly simple: We’re simply using jQuery to assign an onClick event to our cap (with a CSS ID of “open”) and our close button (which we called “#close” last week). When the user clicks on either of those elements, the function inside (openAd and closeAd, respectively) will trigger. After that, we’ve included a “return false,” which simply tells the browser not to bother following the href in our anchors (it was blank anyway, but we don’t want the page refresh that would go along with an attempt).

And now, one last line of jQuery magic. When we open our page, we want our ad to pop out of the side of the page, catching the user’s eye and drawing their attention to our box’s content. To do that, we use this line:

$(popOut).animate({opacity: 1.0}, 1500, "linear", openAd);

jQuery is very powerful, but one thing it lacks is a simple “delay” function. And here’s the problem: I don’t want my ad to start animating the very instant that my document becomes “ready.” For one, I’d like the reader to be able to orient themselves on the page. For another, just because the document is ready (i.e., our code has downloaded) doesn’t mean that all of my images have finished downloading. And an animated ad without any images is far less impressive than the image-rich variety.

Luckily, I found a solution on a blog titled “Panagiotis Karageorgakis,” and modified it to fit my needs. The basic concept is this: we animate the ad in some way that makes absolutely no change whatsoever on the screen, and then we chain on a second animation when we’re done.

So here, our animation, which will fire on load, tells jQuery to slowly set the opacity of our ad to “1.0” (opaque) over the course of 1.5 seconds. Of course, our ad was already fully opaque, so this has no effect at all. And then after the first “animation” is completed, we fire off another function: namely, our openAd function, which will do all the heavy lifting involved in actually opening our ad.

And that’s all there is to it! We now have a fully functioning popout ad. You can see it in action here. And here’s the completed JavaScript, so you don’t have to hunt it down:

$(document).ready(function() {
	var popOut = "#popout";
	var adBox = "#adbox"; 
	var adWidth = $(adBox).width() + $(".cap").width();

	function openAd() {
		$(popOut).width(adWidth+"px");
		$(adBox).animate({marginLeft: "0"},1200);
	}
	
	function closeAd() {
		$(adBox).animate({marginLeft: "-"+adWidth+"px"},1200,"linear",
			function(){ $(popOut).width($(".cap").width() + "px"); }
		);
	}

	$("#open").click(function() {
		openAd();
		return false; 
	});
	$("#close").click(function() {
		closeAd();
		return false;
	});	
	
	$(popOut).animate({opacity: 1.0}, 1500, "linear", openAd);
});

Of course, that isn’t to say we couldn’t make our ad a little fancier than it is. Next week, we’ll go over some ways to make the ad even more advanced – like remembering whether the ad should be open or closed, or letting the user open and close the ad by clicking on the cap. Stay tuned!

Note: Part 3 of this series is available here. And if you missed it, here’s part 1.

17 Responses

  1. Rob (reply)

    Hi ReTox, thanks for the heads up. It’s technically not a bug in the JavaScript, but a bug in Opera itself.

    Here’s the deal: Opera respects the negative margin we give the ad initially, and it respects the new margin fed to it by jQuery’s animation function as long as the ad is moving. But when jQuery sends it the final left margin of “0,” Opera seems to get confused and reverts back to the original margin of -300, effectively hiding the close button behind the cap and off the edge of the page.

    However, we’ve found a pretty easy fix. In the CSS, instead of positioning the close button against the right side of our ad with a “right: 0″ rule, we can put it into place with a “left” rule instead, pushing it away from the left side. I’m not sure why this prevents the bug from triggering, but it seems to do the trick. I’ve already updated the examples to the new CSS, and I’ll update part 1 of the article to explain the bug and the fix.

    You can also fix this in the jQuery, but it’s less of an elegant solution. I’ve found that, if the animation’s margin never hits zero, the bug is never triggered. So in the openAd function, if you stop the animation at “-1px” instead of at “0”, the bug isn’t triggered. But then you have the leftmost edge of your ad hidden at all times, and that bothers me, which is why I’m opting for the CSS workaround.

  2. Pingback: jQuery-Based Popout Ad: Part 1 - CSSnewbie

  3. Tom OConnor (reply)

    For some reason this won’t work on IE7. And the oddest thing happened when I was working with it, in trying to make sure the button was still in the same place I applied a background color in the CSS, and then it works. So literally, button doesn’t move but it will work with a bg color and won’t without.

  4. Rob Glazebrook (Author) (reply)

    Wow, Tom… you’re right. There’s a pretty major IE7 bug in there. And setting the background color does seem to fix it.

    The problem is, IE7 ignores the size you specify on a link if the content (text, image, whatever) doesn’t take up all the space you’ve given it. And because we’ve set a “display: none” on the content, IE7 can’t find anything to click on. Never mind the fact we’re in “display: block” mode with a specified width and height.

    However, as you pointed out, setting a background color makes it respect the size of our box. Of course, that also obscures our close button.

    We have two options: first, we could just cut the close button out of our ad design, create it as a separate image, and put that in our close anchor. The anchor would be clickable, because it was filled with the image.

    Or two, you can set a background color on the anchor tag, and then HIDE that color by setting its opacity to zero. IE7 still respects our size for whatever reason. Unfortunately, there seems to be an opacity bug in IE6 wherein the opacity filter doesn’t take into account positioned elements: the close button becomes transparent all the way down to the document underneath. So if you need IE6 support, this isn’t the best option. But it works elsewhere.

  5. Rob Glazebrook (Author) (reply)

    …and now that I’ve said that, I’ve come up with a third, better, option.

    Instead of using a background color, use a background image instead. It turns out that a repeated background image works just as well to give the anchor its proper size. So I’ve created a 1×1 transparent gif and set that as the anchor’s background in my CSS. The close button now works. I’ll get the example updated right away, and then update the tutorial soon.

  6. Carlos @ VPSmedia (reply)

    Wow really cool. Can this be done with say a form? being able to use it to display a login form would be interesting.

  7. Bill (reply)

    Rob,
    Many thanks for this tutorial. It is very good. I have a question that I am not sure about. It opens fine, the image is full, but if
    I move the mouse, it looks like about 20PX disappears from the right
    side of the image. I am using IE 7 and Firefox 3.10, it is the same.

  8. Andy (reply)

    #popout #cap {position:relative}

    should be

    #popout #cap {position:absolute}

    Otherwise IE7 doesn’t work properly.

  9. Kai (reply)

    Hi, this is really a great article!!! What do I have to change if I want the popout to open from right to left? I want to place the reminder on the right side of my website and to open the popout from right to left.

  10. Pingback: jQuery-Based Popout Ad: Part 3

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>