Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

jQuery.position() on Invisible Elements fails


:P
On this page:

Ah, just ran into a tricky issue with jQuery’s .position() function. position() returns the top and left position relative to its offset parent. For absolutely positioned elements in most cases this allows you retrieve the document relative position of the element to get an absolute page relative position. I use this function in many places of my internal library to move things around and resize them – it’s a handy function that I’m glad was integrated into the jQuery core.

So to retrieve the current position an object with left and top properties is returned:

var pos = $("#divHover").position();
alert(pos.left + " " + pos.top);

This works great if the selected element is visible. However if the object – as in my case – is initially invisible and you call position you get an exception:

[Exception... "Could not convert JavaScript argument arg 0 [nsIDOMViewCSS.getComputedStyle]"  nsresult: "0x80570009 (NS_ERROR_XPC_BAD_CONVERT_JS)"  location: "JS frame :: http://localhost/jqueryWeb/scripts/jQuery.js :: anonymous :: line 878"  data: no]
http://localhost/jqueryWeb/scripts/jQuery.js
Line 878

This rather cryptic error occurs somewhere deep down in the jQuery stack as it’s trying to retrieve offsets from parent controls. Apparently most browsers don’t  create the internal computed styles that are used to retrieve more reliable style information when the element is not visible with the styles simply not appearing in the list. The result is the error above.

The workaround is to make the element visible first so the following fixes the problem:

var pos = $("#divHover").show().position();
alert(pos.left + " " + pos.top);

Now in my case I have this code in some generic code in my library so this is a little more tricky – I have to detect whether the element is visible and then grab the position then hide it again. Here’s what this code looks like where el is the jQuery wrapped set for the matched element:

var vis = el.is(":visible");
if (!vis)
    el.show();  // must be visible to get .position

var pos = el.position();

if (!vis) 
    el.hide();

This was a bugger to find, because this code is already buried deep in my own codebase and it works most of the time except of course when the original object is invisible. Hopefully this will help somebody out running into a similar issue.

Posted in jQuery  JavaScript  

The Voices of Reason


 

aaron
September 22, 2008

# re: jQuery.position() on Invisible Elements fails

I believe Prototype does something like set visibility:hidden, position:absolute, and display:block before getting the element's position. Afterward it resets these css props to their original values.

This way the element is still "invisible" when getting it's position.

Rick Strahl
September 22, 2008

# re: jQuery.position() on Invisible Elements fails

aaron, I don't think that really matters much because the above code happens so fast that it's invisible. Also I think the DOM doesn't immediately update the display in many cases (especially in some browsers like IE) so I would think it's probably ok to forego the visibility. Also setting visibility:hidden may still shift around the UI a bit if the element is relative in any way and if visibility is affected.

Siderite
September 23, 2008

# re: jQuery.position() on Invisible Elements fails

Rick, I've had a similar experience a few days ago and I racked my brains for a day before realising that in FireFox (and not in IE) the offset properties (like parent,top, left, etc) are NOT set until the page has been completely loaded. Which may seem reasonable except that this fails completely when using inline javascript blocks that change the DOM. I believe the script engine never acknowledges the page as loaded if before finishing a script changes the DOM.

It might be a different problem whatsoever, since my control was visible all the way through, but it seems very similar to me.This is my entry about it. <a>http://siderite.blogspot.com/2008/09/offsetparent-null-in-firefox-absolute.html</a>.

Also, about the visible/invisible switch being too fast to notice, I wouldn't be so sure. Different browsers do different things in different versions.

Rick Strahl
September 23, 2008

# re: jQuery.position() on Invisible Elements fails

@Siderite - shouldn't you be doing all this in $().ready handlers? Surely if you're injecting HTML inline it doesn't need to be absolutely positioned? Absolute content can live anywhere including at the end of the page.

Doing any sort of positioning before the DOM is loaded probably is not a good idea any way you look at it. If you're injecting inline there should be no reason to work with absolute positioned content - that should be able to wait until DOM's loaded (.ready()), no?

Markus
January 12, 2009

# Position absolute JQuery Datepicker

Hi Rick,
when activating the Datepicker calendar it always pops up wrongly at position (top 397px / left 520px). I could use your code (see above) to find out that the trigger (input) is positioned at 520px / 2215px. Are you aware of a way to position JQuery Datepicker absolutely so that it pops up next to its trigger?
Thanks a lot for your help!
Markus

suleiman
October 17, 2010

# re: jQuery.position() on Invisible Elements fails

Had similar problems, thanks for the post! Worked around the flash that occurs when displaying the element to get the postion or height by setting the visibility to transparent at the same time as I'm displaying it, so the user doesn't see any flashing. Also i set the variable that holds the postion-value locally or else the value is lost again when you hide the element.
/Suleiman

umesh kumar
December 20, 2010

# re: jQuery.position() on Invisible Elements fails

Thanks for your help, i was facing some different issue to fix elements inside the viewport, if we scroll up or down. gr8.. help keep the good work going!!

Kevin Kaland
February 10, 2011

# re: jQuery.position() on Invisible Elements fails

I bumped into this one today too and used the Firebug debugger to figure out what was going on. I just kinda guessed that it had something to do with display visibility.

Here's the funny part - the first time I got this, jQuery simply said the position propery didn't exist. I think this is because the page loaded with the default CSS having set the item to display: none. I got the same error as you once I tried to call .position() on an element that had had its class that made it visible removed.

Funky stuff! I wonder if this is better in later versions of jQuery? This is still with 1.2.6 I think.

Tahir
January 31, 2012

# re: jQuery.position() on Invisible Elements fails

Please suggest any solution for using jquery.position() for <br> element.
it gives me the correct value in firefox but gives 0 in chrome.
please help me.
Thanks in advance

Rick Strahl
January 31, 2012

# re: jQuery.position() on Invisible Elements fails

@Tahir - You can't get a position value for an inline element reliably (nor would you want to because the element will flow with resizing/movement etc.). One thing you can do is make any element positional first (position: absolute) then use position on it.

FWIW, it's a really bad idea to try to manipulate an inline element like <br> and treat it as positional. Use a div or other block element. If necessary wrap whatever you have into a block element.

subhash
March 02, 2012

# re: jQuery.position() on Invisible Elements fails

Thanks..it helps me...

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024