StackSlave
StackSlave

Reputation: 10627

Can anyone explain the strange Object behavior of getBoundingClientRect()?

If you test the following example you'll notice that the console does not log the correct coordinates, .onmouseover of the box. I know I'm getting the cb Object before the .onmouseover, but usually when you access a DOM Object property it gives you the correct value at the time.

var box = document.getElementById('box'), cb = box.getBoundingClientRect();
box.style.margin = '30px';
box.onmousemove = function(e){
  console.log('x:'+(e.clientX-cb.left)+'; y:'+(e.clientY-cb.top));
}
#box{
  width:160px; height:90px; background:#700;
}
<div id='box'></div>

Notice this way works:

var box = document.getElementById('box');
box.style.margin = '30px';
box.onmousemove = function(e){
  var cb = box.getBoundingClientRect();
  console.log('x:'+(e.clientX-cb.left)+'; y:'+(e.clientY-cb.top));
}
#box{
  width:160px; height:90px; background:#700;
}
<div id='box'></div>

Well, it should work, oddly x never seems to hit 0, either (of course I know I can do the math). Is there any valid reason for any of the behavior I've described? I'm using FireFox 69.0.3 (64-bit). Is it a bug? I have a work around. I'm just asking.

Upvotes: 0

Views: 532

Answers (2)

VLAZ
VLAZ

Reputation: 29002

The issue is that in the first instance you take cb before adding the margin.

Since getBoundingClientRect will give you the positions at the point of time it was called, you get a snapshot of the positions without a 30px offset. That's why both x and y never go below 30 in the first example but they do in the second when you get a fresh snapshot of the positions every time.

If you you can get a reliable snapshot once, then the calculation would be correct:

var box = document.getElementById('box');
box.style.margin = '30px';
var cb = box.getBoundingClientRect();
box.onmousemove = function(e){
  console.log('x:'+(e.clientX-cb.left)+'; y:'+(e.clientY-cb.top));
}
#box{
  width:160px; height:90px; background:#700;
}
<div id='box'></div>

Upvotes: 2

Kaiido
Kaiido

Reputation: 136678

That's simply because a DOMRect is not live. That's just like a plain object that get created every time you call one of the methods that return such an object; and even if the originating Element is modified, the DOMRect will still just be whatever it was when it got created.

const target = document.getElementById( 'target' );

const rect_1 = target.getBoundingClientRect();
target.style.width = '120px';
const rect_2 = target.getBoundingClientRect();

console.log( rect_1.width, rect_2.width ); // 10, 120
#target { width: 10px }
<div id="target"></div>

Upvotes: 1

Related Questions