Rick Strahl's Web Log

One of the things that I keep running into in library code I create is that I deal with a lot of elements that are floating/dragging or otherwise being moved around the document as free floating elements. jQuery.ui includes a dead simple Draggable plug-in that handles this easily, but in some situations the draggable plug-in is overkill when I simply need to pop up a dialog on the page on top of other content.

One recurring theme for any of these scenarios is that I have to reliably turn an element into absolute positioning and while sometimes it’s as easy as doing $(this).css("position","absolute"); at other times doing this is not enough as the element will ‘jump around’ on the page into another position as it’s popped out of its document containership hierarchy.

After doing this enough times manually and often forgetting one or another setting I added a small plug-in that does it for me now:

$.fn.makeAbsolute = function(rebase) {

returnthis.each(function() {

var el = $(this);

var pos = el.position();

el.css({ position: "absolute",

marginLeft: 0, marginTop: 0,

top: pos.top, left: pos.left });

if (rebase)

el.remove().appendTo("body");

});

}

If you’re new to jQuery, a plug-in basically extends the jQuery.fn object with a new function that becomes part of the jQuery matched set. The function can be called just like any other jQuery function that operates on the matched set of elements. The function is called in the context of the matched set object – so this is the jQuery instance of all the matched elements. Note that use return this.each() {} to iterate of each of the matched items and return the matched set as a result of the call. This ensures that this function can be used in the call chain of jQuery commands against the matched set and further functions can be called after it.

The plug-in code makes the element absolutely positioned as well as removing margins and explicitly forcing the top and left properties to be set. Removing the margin ensures you don’t get any funky bumping of content that is effectively out of the flow of the document – an important aspect if you’re moving things around say with drag operations or else you end up with really odd offsets. Setting top and left shouldn’t be necessary usually but in some situations where elements are nested deeply inside of other elements the default position will cause elements to be thrown into unexpected page positions. jQuery’s position() function looks at a variety of properties for placement of elements and generally reliable in getting the correct location and explicitly assigning it.

The rebase parameter when set causes the element to be removed from its current document position and instead be attached to the body element. This can be useful in some instances where elements are deeply nested when the container positioning and margins can cause erratic behavior for positioning. For example, I just ran into a situation with an element that was loaded inside of a <fieldset> element and no matter what I tried the absolute position – and the event object offsets that mouse events caused where completely off. Rebasing to the body of the document made this same element work just fine. This option should be avoided if possible as it causes the element to be basically cloned which means any references to the old element become invalid. Rebasing can also cause problems with CSS Selectors both for CSS or jQuery if the element depends on the document hierarchy to be found.

It’s useful – just gone through my library routines and remove about 10 instances where similar code was in use and replaced with this. Maybe some of you may find this useful or give you some ideas on how to get elements absolutely positioned.

The Voices of Reason

Very cool. At minimum, this has was helpful in that I had one of those 'hit my forehead' moments when I realized that I could just be giving an object to .css() rather than calling it once for each property... DUH! (yep, I've only been using Jquery for a few weeks)