JavaScriptDOM and events

Element.getBoundingClientRect()

Returns an element’s size and its position relative to the viewport, as a DOMRect object.

Returns
A DOMRect object with the x, y, width, height, top, right, bottom, and left properties (in CSS pixels).
On this page

Example

#
JavaScript
const card = document.querySelector('#card')

requestAnimationFrame(() => {
  const rect = card.getBoundingClientRect()

  console.log(Math.round(rect.width), Math.round(rect.height))
  console.log(Math.round(rect.left), Math.round(rect.top))
  console.log(Math.round(rect.right), Math.round(rect.bottom))
})
Console
240 80
36 16
276 96

The width includes padding and the border, since the elements in the preview use box-sizing: border-box. left equal to 36 is 16 px of page spacing plus 20 px of the card’s margin, and right is always left + width. The measurement waits for the first frame (requestAnimationFrame()), since the example’s frame gets its size a moment after the script starts. On a normal, already-rendered page, you can measure right away.

Definition and usage

#

The getBoundingClientRect() method measures an element the way it looks on screen. It returns a DOMRect object with width and height properties (size) and top, right, bottom, and left (edge positions). There are also x and y, which for elements equal left and top.

The position is measured relative to the visible window area (the viewport), not the start of the document. When you scroll the page down, the element’s top decreases, and it goes negative for elements above the screen. You get the position relative to the whole page by adding the scroll offset: rect.top + window.scrollY. position: fixed uses the same coordinates, so it’s easy to place something like a tooltip next to an element.

The size includes padding and the border, i.e. the whole area the element occupies. It also accounts for CSS transforms: transform: scale(2) doubles the returned width. Values can come out fractional, for example when the page is zoomed, so it’s worth rounding them before comparing. Reading it can also force the browser to immediately recompute the page layout if styles changed just before.

Syntax

#
Syntax
element.getBoundingClientRect()

More examples

#
CSS transforms change the result
JavaScript
const badge = document.querySelector('#badge')

requestAnimationFrame(() => {
  console.log(badge.offsetWidth)
  console.log(Math.round(badge.getBoundingClientRect().width))
})
Console
100
150

offsetWidth gives the width from the page layout and ignores transform. getBoundingClientRect() measures the element after scaling, i.e. the way it looks on screen.

A tooltip bubble under a button
JavaScript
const help = document.querySelector('#help')
const tooltip = document.querySelector('#tooltip')

help.addEventListener('click', () => {
  const rect = help.getBoundingClientRect()
  tooltip.style.left = `${Math.round(rect.left)}px`
  tooltip.style.top = `${Math.round(rect.bottom + 8)}px`
  tooltip.hidden = false
  console.log(tooltip.style.left, tooltip.style.top)
})

requestAnimationFrame(() => help.click())
Console
56px 60px

The coordinates from getBoundingClientRect() and from position: fixed are measured from the same point, the top-left corner of the viewport. So the tooltip lands 8 px below the button’s bottom edge. We simulate the click on the first frame, once the preview’s frame already has its size.

Browser support

#

Widely available

Works in all modern browsers, phones included. You can use it without worry.

  • Chrome
  • Edge
  • Firefox
  • Safari

Good practices

#
  • The coordinates change when you scroll, since they’re measured from the viewport. The position on the page is rect.top + window.scrollY.
  • Round the results with Math.round() before comparing or displaying them. Values can come out fractional when the page is zoomed.
  • An element hidden with display: none, or not yet inserted into the document, has every dimension equal to 0. Measure it only once it’s displayed.

Related entries

#

Spotted a mistake or missing an example? Write to us.