getBoundingClientRect() is returning zero in XUL
Asked Answered
P

3

18

I have a problem with my firefox extension

I have a XUL popup panel with a hbox for the tag cloud, and a JS code to add divs to this hbox:

<hbox id="tag_base" ondblclick="alert('done')"/>

JS:

var root = document.getElementById('tag_base');
var tag = document.createElement('div');
tag.textContent = 'test';
root.appendChild(tag);
var rect = tag.getBoundingClientRect()
alert(rect.top)

I need to get the dimensions of each added div, however, getBoundingClientRect simply refuses to work. If I remove alerts, it's always zero. With alerts the story is different: The first time the alert is called it returns zero, although the div appears on the screen. Any subsequent alerts return the correct coordinates.

If I set a breakpoint in Chromebug, everything is reported correctly. If I do not interupt the execution in any way, and run a loop, only zeroes got returned.

This has got me quite confused. Calling "boxObject" produces the same results, while "getClientRects[0]" is undefined on the first call.

Any hints on what might be causing this will be greatly appreciated.

Paleogeography answered 1/1, 2011 at 23:28 Comment(1)
See the Neil's answer in a comment. (Not sure if you get notified of comments on answers on SO.)Wellspring
W
11

Although I can't find any documentation on this seemingly fundamental issue, the problem you noticed is most likely because the layout (aka "reflow") process has not yet run by the moment you ask for the coordinates.

The layout/reflow process takes the page's DOM with any styles the page has and determines the positions and dimensions of the elements and other portions of the page (you could try to read Notes on HTML reflow, although it's not targeted at web developers and probably is a bit outdated).

This reflow process doesn't run synchronously after any change to the DOM, otherwise code like

elt.style.top = "5px";
elt.style.left = "15px";

would update the layout twice, which is inefficient.

On the other hand, asking for elements position/dimension (at least via .offsetTop) is supposed to force layout to return the correct information. This doesn't happen in your case for some reason and I'm not sure why.

Please create a simple testcase demonstrating the problem and file a bug in bugzilla.mozilla.org (CC me - ***********@gmail.com).

My guess is that this is related to XUL layout, which is less robust than HTML; you could try creating the cloud in an HTML doc in an iframe or at least in a <description> using createElementNS to create real HTML elements instead of xul:div you're creating with your current code.

Wellspring answered 3/1, 2011 at 20:46 Comment(2)
thank you for the detailed response, I'll submit a test case to bugzilla as you suggested.Paleogeography
This is probably happening because layout doesn't happen for a popup until it's first shown, except in the case of a menulist, because the popup has to layout so that the list can size to it.Bauxite
G
57

Note : Caution, if you use getBoundingClientRect with an element which has display:none then it will return 0, anywhere in the dom.

Giesecke answered 17/1, 2013 at 17:0 Comment(5)
Old post but this is exactly what my problem was.Spiteful
Saved my day! Thank you!Epitome
Thank you so much! I'm using getBoundingClientRect with bootstrap's modal and getting 0 all of them. Then I've tried again with shown.bs.modal, it should work. Thank you again!Freewheel
Still saving people almost 8 years later. Thanks! I had a function that animates elements if on screen, which uses this, and I just realized that it stopped working today. Turns out it's because I added display: none to the whole body for 1 second a few weeks ago.Owens
Thank you! Was using getBoundingClientRect in a scrollTo function. Only the 'scroll to top' links to my <a id="top"></a> tag were not working. That was set to display: none;. Changing it to visibility: hidden; was the fix.Calcaneus
W
11

Although I can't find any documentation on this seemingly fundamental issue, the problem you noticed is most likely because the layout (aka "reflow") process has not yet run by the moment you ask for the coordinates.

The layout/reflow process takes the page's DOM with any styles the page has and determines the positions and dimensions of the elements and other portions of the page (you could try to read Notes on HTML reflow, although it's not targeted at web developers and probably is a bit outdated).

This reflow process doesn't run synchronously after any change to the DOM, otherwise code like

elt.style.top = "5px";
elt.style.left = "15px";

would update the layout twice, which is inefficient.

On the other hand, asking for elements position/dimension (at least via .offsetTop) is supposed to force layout to return the correct information. This doesn't happen in your case for some reason and I'm not sure why.

Please create a simple testcase demonstrating the problem and file a bug in bugzilla.mozilla.org (CC me - ***********@gmail.com).

My guess is that this is related to XUL layout, which is less robust than HTML; you could try creating the cloud in an HTML doc in an iframe or at least in a <description> using createElementNS to create real HTML elements instead of xul:div you're creating with your current code.

Wellspring answered 3/1, 2011 at 20:46 Comment(2)
thank you for the detailed response, I'll submit a test case to bugzilla as you suggested.Paleogeography
This is probably happening because layout doesn't happen for a popup until it's first shown, except in the case of a menulist, because the popup has to layout so that the list can size to it.Bauxite
V
7

Be sure the DOM is ready. In my case, even when using the getBoundingClientRect function on click events. The binding of the events needed to happen when the DOM is ready.

Vandervelde answered 21/12, 2017 at 8:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.