Web developers often need to determine where an element has been placed in the page, or more generally, where it is relative to another element. Existing APIs for doing this have significant limitations. The new GeometryUtils interface and its supporting interfaces DOMPoint, DOMRect and DOMQuad provide Web-standard APIs to address these problems. Firefox is the first browser to implement these APIs; they are available in Firefox 31 Nightly builds.
Current best standardized APIs for retrieving element geometry
Currently the best standardized DOM APIs for retrieving element geometry are element.getBoundingClientRect()
and element.getClientRects()
. These return the border-box rectangle(s) for an element relative to the viewport of the containing document. These APIs are supported cross-browser but have several limitations:
- When complex CSS transforms are present, they return the smallest axis-aligned rectangle enclosing the transformed border-box. This loses information.
- There is no way to obtain the coordinates of the content-box, padding-box or border-box. In simple cases you can add or subtract computed style values from the results of
getBoundingClientRect()
/getClientRects()
but this is clumsy and difficult to get right. For example, when a <span> breaks into several fragments, its left border is only added to one of the fragments — either the first or the last, depending on the directionality of the text. - There is no way to obtain box geometry relative to another element.
Introducing getBoxQuads()
The GeometryUtils.getBoxQuads()
method, implemented on Document
, Element
and TextNode
, solves these problems. It returns a list of DOMQuad
s, one for each CSS fragment of the object (normally this list would just have a single
DOMQuad
).
Example:
var quads = document.getElementById("d").getBoxQuads();
// quads.length == 1
// quads[0].p1.x == 100
// quads[0].p1.y == 100
// quads[0].p3.x == 200
// quads[0].p3.y == 200
Using bounds
A DOMQuad
is a collection of four DOMPoint
s defining the corners of an arbitrary quadrilateral. Returning DOMQuad
s lets getBoxQuads()
return accurate information even when arbitrary 2D or 3D transforms are present. It has a handy bounds
attribute returning a DOMRectReadOnly
for those cases where you just want an axis-aligned bounding rectangle.
For example:
var quads = document.getElementById("d").getBoxQuads();
// quads[0].p1.x == 150
// quads[0].p1.y == 150 - 50*sqrt(2) (approx)
// quads[0].p3.x == 150
// quads[0].p3.y == 150 + 50*sqrt(2) (approx)
// quads[0].bounds.width == 100*sqrt(2) (approx)
Passing in options
By default getBoxQuads()
returns border-boxes relative to the node’s document viewport, but this can be customized by passing in an optional
options dictionary with the following (optional) members:
box
: one of"content"
,"padding"
,"border"
or"margin"
, selecting which CSS box type to return.relativeTo
: aDocument
,Element
orTextNode
;getBoxQuads()
returns coordinates relative to the top-left of the border-box of that node (the border-box of the first fragment, if there’s more than one fragment). For documents, the origin of the document’s viewport is used.
Example:
var quads = document.getElementById("e").getBoxQuads({
relativeTo:document.getElementById("d")
});
// quads[0].p1.x == 0
// quads[0].p1.y == 0
quads = document.getElementById("e").getBoxQuads({
relativeTo:document.getElementById("d"),
box:"content"
});
// quads[0].p1.x == 20
// quads[0].p1.y == 20
The relativeTo
node need not be an ancestor of the node receiving getBoxQuads()
. The nodes can even be in different documents, although they must be in the same toplevel browsing context (i.e. browser tab).
Scratching the surface
If you’ve read this far, you’re probably observant enough to have noticed additional methods in GeometryUtils — methods for coordinate conversion. These will be covered in a future blog post.
About roc
Robert O'Callahan is a distinguished engineer at Mozilla Corporation. Prior to joining MoCo he was a volunteer Mozilla contributor for several years (since 2000).
About Robert Nyman [Editor emeritus]
Technical Evangelist & Editor of Mozilla Hacks. Gives talks & blogs about HTML5, JavaScript & the Open Web. Robert is a strong believer in HTML5 and the Open Web and has been working since 1999 with Front End development for the web - in Sweden and in New York City. He regularly also blogs at http://robertnyman.com and loves to travel and meet people.
10 comments