getBoundingClientRect is lame (for SVG elements)

posted 2012-May-16

The CSSOM View working draft put forth by the W3C introduced a new JavaScript method that’s pretty helpful: getBoundingClientRect().

Given an element in a web page, this method returns the actual position of the element on screen, regardless of CSS positioning and where layout engine wrapped it. Or at least, that’s the idea.

The problem comes when you have SVG elements embedded in your page, specifically when those elements are transformed in a way that changes rectangle shapes (e.g. rotation or skew).

Seen above are two SVG <circle> elements; the second one has been rotated 45°. JavaScript then uses getBoundingClientRect() to place some blue <div>s around each circle. The question/problem is: Why is the one on the right so much larger than the circle?

The answer can be seen in the dotted line. If we take the local (rotated) bounding box of the circle, transform just the corner points of that box into screen space, and then calculate the bounding box of those points, we get the answer arrived at by getBoundingClientRect().

In my opinion the various working groups within the W3C need to collaborate a little bit more tightly, and find a way to specify that the ‘bounding client rect’ is, in fact, the minimal, axis-aligned bounding rect and not something sort of like that.


Update: Firefox behaves differently (as desired, but inconsistent with all other browsers)! So now I just need to get Webkit, Opera, and IE to ‘fix’ their implementations. :/

Jonathan
08:57PM ET
2012-May-16

One should be careful with those absolute coordinates since there are not valid anymore after any repositioning. For example if the objects are contained in a centered element, a simple scrollbar appearance will invalidate the previous values.

Gavin Kistner
09:47PM ET
2012-May-16

@Jonathan Yes, resizing this simple test case will cause the divs to be placed away from the circles. (Though some might say this was a “feature”, since the return value of getBoundingClientRect() is similarly and explicitly specified to be correct when called, and not updated live. ;)

net.mind details other résumé contact
Phrogz.net