Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Short answer: Element.getBoundingClientRect() already includes CSS zoom. Read left, top, width, and height directly; multiplying them by the zoom value again produces incorrect, double-scaled coordinates. The returned rectangle is relative to the layout viewport and measured in CSS pixels.
“Screen coordinates” can mean several different systems. The code below shows viewport coordinates, document coordinates, the currently visible mobile visual viewport, and why none of those values should automatically be treated as operating-system or physical display pixels.
What getBoundingClientRect() returns under CSS zoom
Calling element.getBoundingClientRect() returns a DOMRect describing the element’s border box. Its left, top, right, and bottom edges and its width and height are viewport-relative CSS-pixel values. Padding and borders are included.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11CSS zoom is already reflected in those values. If an element is laid out at 200% zoom, its returned rectangle describes the rendered, enlarged geometry. Do not multiply the result by 2, by element.currentCSSZoom, or by any other CSS zoom factor.
#1 Best Overall
const target = document.querySelector('.target');
const rect = target.getBoundingClientRect();
console.log({
left: rect.left,
top: rect.top,
right: rect.right,
bottom: rect.bottom,
width: rect.width,
height: rect.height
});
The rectangle’s origin is the top-left corner of the layout viewport. Scrolling changes left and top for a fixed document element because the element moves relative to that viewport.
Choose the coordinate system before writing conversion code
Most coordinate bugs come from combining values that use different origins, units, or zoom rules. Decide which of these targets you actually need.
Viewport-relative CSS coordinates
Use this space for an overlay positioned with position: fixed, a tooltip tied to what is visible, or another element whose origin is the viewport.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesconst rect = target.getBoundingClientRect();
const viewportPoint = {
x: rect.left,
y: rect.top
};
const viewportSize = {
width: rect.width,
height: rect.height
};
These numbers are CSS pixels, not physical monitor pixels. A negative top or left is normal when part of the target has scrolled outside the viewport.
Document-relative CSS coordinates
For a point relative to the document’s top-left origin, add the page scroll offset. This changes the origin; it does not convert CSS pixels to device pixels.
const rect = target.getBoundingClientRect();
const documentLeft = rect.left + window.scrollX;
const documentTop = rect.top + window.scrollY;
const documentRect = {
left: documentLeft,
top: documentTop,
width: rect.width,
height: rect.height
};
Use a document-positioned overlay (for example, an absolutely positioned layer inside the same document) when consuming these values. Do not add scroll offsets and then assign the result to a fixed-position element, or the overlay will drift as the page scrolls.
Coordinates in the currently visible mobile viewport
Pinch zoom, an on-screen keyboard, and browser interface changes can make the visual viewport differ from the layout viewport. If your feature follows the area the user can currently see, inspect window.visualViewport.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
const vv = window.visualViewport;
if (vv) {
console.log({
visualLeft: vv.offsetLeft,
visualTop: vv.offsetTop,
visualWidth: vv.width,
visualHeight: vv.height,
visualScale: vv.scale
});
}
visualViewport.scale describes visual-viewport scaling; it is not a replacement multiplier for a DOMRect. Treat the viewport offsets and dimensions as a separate coordinate-space description and test interactions on the mobile browsers you support.
Operating-system or physical display coordinates
A DOM rectangle is not a universal hardware-screen rectangle. Browser-window placement, device pixel ratio, page zoom, operating-system display scaling, and mobile visual-viewport state all affect any conversion to physical pixels. The browser APIs in this article establish CSS geometry, not one cross-platform formula for desktop screen coordinates.
If an automation or native integration requires physical pixels, define the browser, operating system, display scale, window placement, and origin convention first, then validate a conversion in that exact environment. Never label rect.left as a hardware coordinate without those qualifications.
CSS zoom versus transform: scale()
zoom and transform: scale() can look similar but have different layout behavior.
Free tools Windows power users keep installed
One-click scans. No signup required.
| Property | Layout behavior | Measurement implication |
|---|---|---|
zoom |
Magnifies or reduces an element and can change layout and the placement of surrounding content. | getBoundingClientRect() reports the scaled rendered rectangle. |
transform: scale() |
Applies a visual transform without recalculating layout in the same way; surrounding flow is not moved as a normal resize would. | The rectangle reflects the transformed visual bounds, but layout measurements such as offsets describe a different concept. |
Choose the property based on the behavior you need. Do not infer CSS zoom semantics from experiments with transforms, and do not mix their measurements without deciding whether you want layout geometry or painted geometry.
A complete overlay example
This example places a fixed overlay directly beneath a zoomed target. It reads the rectangle as-is and updates on scroll and resize.
<style>
.target { zoom: 1.5; margin: 240px 0 0 180px; width: 220px; padding: 16px; border: 3px solid #2463eb; }
.overlay { position: fixed; z-index: 10; padding: 6px 9px; color: white; background: #111827; pointer-events: none; }
</style>
<div class="target" id="target">Zoomed target</div>
<div class="overlay" id="overlay" hidden>Overlay</div>
<script>
const target = document.getElementById('target');
const overlay = document.getElementById('overlay');
function positionOverlay() {
const rect = target.getBoundingClientRect();
overlay.hidden = false;
overlay.style.left = `${rect.left}px`;
overlay.style.top = `${rect.bottom}px`;
}
addEventListener('scroll', positionOverlay, { passive: true });
addEventListener('resize', positionOverlay);
positionOverlay();
</script>
Because both the target rectangle and the fixed overlay use viewport CSS pixels, no zoom multiplication or scroll adjustment is needed.
Rank #3
Comparing DOM measurement APIs without mixing units
Not every geometry API incorporates CSS zoom in the same way. getBoundingClientRect() reports scaled lengths. Client properties, offset properties, and scrolling APIs are examples of measurements that do not follow the same scaling rule.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →| API or value | Typical reference | CSS zoom caution |
|---|---|---|
getBoundingClientRect() |
Rendered border-box rectangle relative to the viewport | Includes CSS zoom; use directly for rendered viewport geometry. |
clientWidth, clientHeight |
Inner dimensions including padding, excluding borders and scrollbars | Not scaled in the same way; do not compare directly to rect.width without an intentional conversion. |
offsetWidth, offsetHeight |
Layout dimensions including borders | Not scaled in the same way as the rectangle APIs. |
scrollWidth, scrollHeight |
Scrollable content dimensions | Use with care when CSS zoom changes rendered geometry. |
If you must compare an offset or client value with a rectangle, document which quantity each represents and convert deliberately. A ratio that appears to be the zoom factor may instead include borders, scrollbars, rounding, transforms, or nested zoom.
currentCSSZoom and nested zoom values
Element.currentCSSZoom reports the effective CSS zoom for an element, including zoom values inherited from ancestors. For example, ancestor zoom values of 2 and 3 combine to an effective value of 6. This property is useful when diagnosing why unscaled APIs differ from rendered geometry; it is not a multiplier to apply to a rectangle.
const effectiveZoom = target.currentCSSZoom;
const rect = target.getBoundingClientRect();
console.log('effective CSS zoom:', effectiveZoom);
console.log('rendered width:', rect.width); // already zoom-aware
MDN documents currentCSSZoom as newly available since March 2026. If your application supports older browser releases, feature-detect it and provide a fallback rather than assuming it exists.
const effectiveZoom = 'currentCSSZoom' in target
? target.currentCSSZoom
: null;
CSS zoom itself is broadly available in current browsers, but older browser matrices may differ. Check the exact versions in your support policy.
Common failure modes and fixes
The coordinates are exactly twice as large
Cause: The code multiplied a rectangle value by a zoom: 2 value even though the rectangle already includes zoom.
Fix: Remove the multiplication and use rect.left, rect.top, rect.width, and rect.height directly.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
An overlay moves when the page scrolls
Cause: Viewport coordinates were assigned to a document-positioned element, or document coordinates were assigned to a fixed element.
Fix: Use rectangle values with position: fixed. For document coordinates, add window.scrollX and window.scrollY and position the overlay in a matching document coordinate system.
Width disagrees with offsetWidth
Cause: The values describe different geometry and do not incorporate CSS zoom identically. Borders, scrollbars, transforms, and fractional rounding can add differences.
Fix: Use getBoundingClientRect() for rendered placement. Use offset or client properties only when their layout-specific definition is what you need.
Mobile coordinates are wrong after pinch zoom or keyboard display
Cause: The layout viewport and visual viewport no longer cover the same visible area.
Fix: Read window.visualViewport, including its offsets and dimensions, and test the interaction on each target mobile browser.
Recommended Free Tools
The target rectangle is empty or unexpected
Cause: The element may not exist yet, may be display: none, may have no rendered boxes, or the measurement may run before layout-affecting styles and content have settled.
Best Value
Fix: Query after the element is present and visible, then measure after relevant styles, fonts, images, and asynchronous content have loaded. Re-measure after changes that affect layout.
Coordinates contain decimals
Fractional CSS pixels are normal, especially with zoom, transforms, responsive layout, and high-density displays. Preserve the fractional values for browser positioning. Round only at the final boundary if an external system requires integer coordinates, and state whether you rounded or truncated.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Performance and reliability practices
- Measure only when needed. For continuous movement, schedule reads with
requestAnimationFrameinstead of forcing a read in every event callback. - Batch DOM reads before writes. Calling
getBoundingClientRect()after many style writes can trigger a synchronous layout calculation. - Listen for scroll and resize when an overlay must track the target; remove listeners when the component is destroyed.
- Use
ResizeObserverwhen target size changes independently of the viewport, and still account for scrolling. - Recalculate after fonts, images, lazy content, or CSS classes change the layout.
- Keep one explicit coordinate-space contract in shared code: origin, unit, viewport type, and whether CSS zoom is already included.
For nested zoom, fractional values, RTL layouts, sticky positioning, and mobile visual-viewport changes, verify behavior in the browser versions and devices that matter to your product. The specification guarantees scaled rectangle lengths, but your integration’s final coordinate conversion may depend on platform details outside the DOM API.
Or skip the browser setup
If your goal is to capture a page rather than position an in-page overlay, ScreenshotNeo provides a one-request screenshot API. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each behavior can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
See the full parameter reference in the ScreenshotNeo documentation.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', buffer));
ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Its free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Does scrolling change a getBoundingClientRect() value?
Yes. The rectangle remains viewport-relative, so a fixed document element’s top and left change as the page scrolls.
Should I round DOMRect values before setting CSS positions?
Usually no. Keep fractional CSS pixels for browser positioning and round only when an external API requires integer coordinates.
Is currentCSSZoom supported everywhere?
It is documented as newly available since March 2026. Feature-detect it if older browser releases are in your support matrix.
Can I use rect.left as a Windows screen coordinate?
Not reliably. It is a viewport CSS-pixel coordinate; physical screen conversion depends on browser, window, operating system, display scale, and viewport state.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.

