Grow your CSS skills. Land your dream job.

jQuery UI’s Position Function (plus, MagicZoom from scratch)

Published by Chris Coyier

Knowing how to position things where you want them is one of the most important tools in a web designer's toolbox. Understanding page flow, understanding everything is a box, understanding floats, etc. Once the basics are learned, a common question for an intermediate designers is how to position elements relative to other elements. The standard CSS solution for this is to use the ol' absolute positioning inside relative positioning trick. In a nutshell, you can use set relative positioning (or really, any positioning that isn't the default static) on an element and then absolutely position child elements of it within that context. A lot of times, this works wonderfully well, but it's actually quite limited:

  • Forced to use positioning value other than static, even if otherwise unneeded
  • Elements trying to be positioned based on the other must be child elements
  • If the parent needs and overflow value it can get awkward

jQuery UI now has a position utility function that makes the job of positioning elements relative to other elements deliciously easy! Let's take a look.

First things first

We'll be using jQuery and jQuery UI here, so we are assuming you are loading the jQuery and jQuery UI libraries on your site.

<head>
...
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
...
<script type="text/javascript">
$(function() {
     // do stuff, yay!
});
</script>
</head>

The Basics

One of the sweet things about jQuery and jQuery UI is the almost sentence-like syntax of writing it. One-word function names and parameters that really drive home what is going on. Here is a basic example.

$("#move-me").position({
	"my": "right top",
	"at": "left bottom",
	"of": $("#thing")
});

Maybe a little graphic will help:

The coolest part here is that there are no prerequisites for this to work. The element being positioned doesn't need any special CSS positioning value (or to be a child element), the element being positioned against doesn't need any special CSS positioning value (or anything else).

All Options

Here is the full set. Only just a few more options.

$('.positionable').position({
	"my": "right top"       //  Horizontal then vertical, missing values default to center
	"at": "left bottom"     //  Horizontal then vertical, missing values default to center
	"of": $('#parent'),     //  Element to position against 
	"offset": "20 30"       //  Pixel values for offset, Horizontal then vertical, negative values OK
	"collision": "fit flip" //  What to do in case of 
	"bgiframe": true        //  Uses the bgiframe plugin if it is loaded and this is true
});

We covered "my", "of", and "at" in the basics, but the full set of parameters include setting an offset, using the bgiframe plugin (fixes some IE z-index issues), and collision detection, which I'll cover later.

Magic Zoom!

I thought I'd throw together a little "real world" example of where this could be useful. Have you ever seen a plugin or other JavaScript effect where you click on an image and it "grows in place"? I'll call it Magic Zoom because I like giving lame names to things. This is how it might work:

  1. Have a grid of thumbnail size images (keeps page load size down)
  2. When a thumbnail is clicked...
  3. Load the full size image directly over top the thumbnail, scaled down to the exact same size
  4. Animate the new full size image up to it's original size
  5. During the animation, keep the image centered over the thumbnail
  6. Click to close

HTML of gallery

The gallery is simply anchor tags that link to the large version, and within, image tags of the thumbnails. Without JavaScript, still totally functional.

<div class="gallery">

	<a href="http://farm4.static.flickr.com/3329/4556228155_7ce08c45a3.jpg">
	  <img src="http://farm4.static.flickr.com/3329/4556228155_7ce08c45a3_m.jpg" alt="" />
	</a>
	
	<!-- More... -->
	
</div>

jQuery JavaScript

$(function() {

    var $el;

    $(".gallery a").live("click", function() {    
     
        $el = $(this);
    
        $("<img />", {
        
            "src": $el.attr("href"),
            "class": "larger"
        
        }).load(function() {
        	        
            $(this)
                .appendTo("body")
                .width($el.find("img").width())
                .position({
                    "of": $el.find("img"),
        			"my": "center center",
        			"at": "center center"
			     })
                .animate({
                    width: 500, // width of large image
                    }, {
                        "duration": 1000, // 1000 = 1 second
                        "easing": "easeOutQuad",
                        "step": function(i) {
                            $(this).position({
                                "of": $el.find("img"),
                    			"my": "center center",
                    			"at": "center center",
                    			"collision": "fit"
            			     })
                        }
                    
                    }
                )
        });
        
        return false;
        
    });

	$(".larger").live("click", function() {
	    $el = $(this);
		$el.fadeOut(400, function() {
			$el.remove();
		})
	});

});

The interesting concept here is the "step" parameter for the animate function. You can give that parameter a function, and that function will run on every single keyframe of the animation. For us, that means we will use the position function to make sure the large image is still centered over it's thumbnail.

View Demo   Download Files

Yeah... the growing of the images is a little shaky. If anyone has any ideas there, let me know.

Collision detection!

Being able to set elements relative to other element with such simple syntax and little code is awesome, but what really sets this position utility above and beyond is collision detection.

What if where we tell the element to be ends up being outside the browser window? That could be a problem, depending on the situation. Take our Magic Zoom example. Theoretically the reason people are clicking the images to see a larger version is because they actually are interested in photo and want to see it larger in more detail. It doesn't help them if the image is along the left edge of the page and gets cut off as the new one grows.

Dealing with this problem is extremely easy with the position function. All we need to do is add the collision parameter with the value "fit" and the position function will ensure that whatever it is positioning is never outside the window.


By default, the larger images try to grow remaining centered over the thumbnail.

Should growing the larger image push it outside the browser window, the position utility will detect that and grow the image inward instead.

Comments

  1. Permalink to comment#

    This is a really useful idea…Thanks For Sharing

  2. Willson
    Permalink to comment#

    Thanks Chris! This could be useful for my site upgrade I’m doing.

  3. Permalink to comment#

    Thank you Chris,

    I enjoy reading your site, i learn a lot from your posts and screencasts

  4. Permalink to comment#

    Thanks for the video. I didn’t really understand what the collision detection was for because my screen resolution is very high.

  5. Permalink to comment#

    Cool!
    jQuery and Chris are awesome!
    My basic CSS and jQuery learned from Chris!

    This script has an error on IE6 and IE7 but on IE8 works great(the jQuery effect, the style is still bad).
    The people I build websites still using IE6 and the viewers to.

    So Thanks a Lot!

  6. James P
    Permalink to comment#

    have you thought about letting the images collide with each other and maybe shrinking to accommodate each other?? this might be really cool

    -James

  7. Permalink to comment#

    Although pretty cool, this breaks when you click on another image as one is being animating. I believe why it breaks and starts stacking the images on top of each other is because the click event sets the absolute coordinates. I’m wondering if you wrapped the .live click event in an if statement you would prevent this problem. I could be wrong though.

    I would think the reason why it’s jittery when it’s animating is because it’s constantly checking it’s self against the window?

  8. Permalink to comment#

    jittery and to slow.Not really an option for an live project but thanks for sharing!:)

    • Permalink to comment#

      Zooming in JavaScript always looks terrible due to the nature of adjusting CSS values in sequence. I don’t know think there is really any way around that, but you can make it less perceptible by adjusting the timer.

  9. Great tutorial, i need to try this when i have time.

  10. Neat example Chris but couldn’t you come up with a more original name?!

    • Sorry about the name conflict there! I named it that because that’s what this exact effect is called in this eCommerce software I have used.

  11. thanks chris I am leaning css and Jquery tricks from this website

    thanks

  12. dcp3450
    Permalink to comment#

    by randomly clicking the images I could make them disappear.

  13. I loved the Vimeo video! I am gonna use your piece of code on my blog and this time I am not going to use anybody’s plugin! I will do it everything by myself! :)

  14. Thanks Chris. jQuery UI is awesome.

  15. John

    Can you show us how to do the actual http://www.magictoolbox.com/magiczoom/ next! :-P

    Thanks for the great article.

  16. awesome tutorial thanks

  17. flep

    Nice plugin, just need some polish, to block the click till the bigger image loads, and show some loading.

    If you just keep clicking the image before the bigger image loads, it will load as many as you clicked!

  18. Another pearler Chris! As always, you make something difficult, seem simple to understand ;) Cheers, Steve

  19. Very cool effects. Previously I was just using a hover function to enlarge the pictures.

    But this is much better.

  20. Hey Chris:

    One thing i noticed. If you click multiple images too fast you not only throw the images all over the page, but you also loose some images on the page.

  21. Orson

    If i double click on a image, it gets zoomed half way. Then if i click on an image next to it just immediately, that image gets zoomed fully but also gets positioned at the top left corner of the screen. Then if i click on this zoomed in image, it gets deleted from the screen.

    T

  22. Orson

    If i double click on a image, it gets zoomed half way. Then if i click on an image next to it just immediately, that image gets zoomed fully but also gets positioned at the top left corner of the screen. Then if i click on this zoomed in image, it gets deleted from the screen.

    That’s my experience trying it out.

  23. Hmm, looks interesting, but dont use JS to often – this is “style vs. userperformance”. Well, you can do postitions with css, use it if you dont need more. kind regards

  24. Sergiu
    Permalink to comment#

    Thank you! The first site that explained jQuery Dialog Position to me like I’m 5 years old. And I finally got it!

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".