Element.getBoundingClientRect() already accounts for CSS zoom. Use its left, top, width, and height as viewport-relative CSS-pixel values; do not multiply them by the zoom factor again. To express the same point in document coordinates, add window.scrollX and window.scrollY. “Screen coordinates” can also mean browser-window or physical display pixels, which require a separate, platform-specific conversion.
What getBoundingClientRect() returns under CSS zoom
A call to element.getBoundingClientRect() returns a DOMRect describing the element’s rendered border box. The rectangle includes padding and borders, is relative to the viewport’s top-left corner, and uses CSS pixels. CSSOM View specifies that rectangle APIs return scaled lengths, so CSS zoom is already reflected in every rectangle edge and dimension.
Consequently, this is correct:
const rect = element.getBoundingClientRect();
const viewportLeft = rect.left;
const viewportTop = rect.top;
const viewportRight = rect.right;
const viewportBottom = rect.bottom;
const viewportWidth = rect.width;
const viewportHeight = rect.height;
This is not correct:
const rect = element.getBoundingClientRect();
const zoom = 2;
const wrongLeft = rect.left * zoom;
const wrongWidth = rect.width * zoom;
Multiplying the rectangle again double-counts CSS zoom and moves the result too far. A zoom value of 1 (or 100%) is normal size; 2 (or 200%) magnifies the rendered page, while values below 1 reduce it.
Choose the coordinate system before writing code
The phrase “screen coordinates” is ambiguous. Decide which origin and unit your consumer expects, then keep every measurement in that same system.
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 →#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
| Coordinate space | Origin and unit | How to obtain it | Typical use |
|---|---|---|---|
| Viewport | Top-left of the current layout viewport; CSS pixels | Use rect.left and rect.top directly |
Fixed overlays, hit regions, alignment with viewport-based UI |
| Document (page) | Top-left of the document; CSS pixels | Add window.scrollX and window.scrollY |
Absolute page coordinates and scroll-independent annotations |
| Visual viewport | The portion currently visible on a mobile device; CSS pixels | Inspect window.visualViewport |
Pinch zoom, browser UI movement, or an on-screen keyboard |
| Browser-window or physical display | Window or hardware-display origin; platform-dependent units | No universal formula is established by these DOM APIs | Operating-system automation and native integrations |
A DOMRect is therefore not automatically a hardware “screen-pixel” rectangle. Browser-window placement, device-pixel ratio, page zoom, and visual-viewport state can all affect a conversion to display pixels. Define the target browser and operating system, and validate that conversion in the environment where it will run.
Convert viewport coordinates to document coordinates
Scrolling changes a fixed element’s viewport-relative rectangle because the viewport origin stays put while the document moves. Add the current page offsets to change the origin to the document:
function getDocumentRect(element) {
const rect = element.getBoundingClientRect();
return {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY,
right: rect.right + window.scrollX,
bottom: rect.bottom + window.scrollY,
width: rect.width,
height: rect.height
};
}
const target = document.querySelector('.target');
const pageRect = getDocumentRect(target);
console.log(pageRect.left, pageRect.top);
The width and height do not need a scroll adjustment: scrolling changes position, not the element’s dimensions. This conversion still produces CSS pixels; it does not convert to device or operating-system pixels.
Position an overlay without double-scaling
Overlay fixed to the viewport
Use the rectangle directly when the overlay is position: fixed. Both the rectangle and the overlay use the viewport as their origin.
const target = document.querySelector('.target');
const overlay = document.querySelector('.overlay');
const rect = target.getBoundingClientRect();
overlay.style.position = 'fixed';
overlay.style.left = `${rect.left}px`;
overlay.style.top = `${rect.bottom}px`;
overlay.style.width = `${rect.width}px`;
Overlay positioned in document space
For an absolutely positioned overlay whose containing block is the document, add the scroll offsets. Make sure the overlay’s containing block really uses the document origin; a positioned ancestor can establish a different origin.
Rank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
const rect = target.getBoundingClientRect();
const left = rect.left + window.scrollX;
const top = rect.top + window.scrollY;
overlay.style.position = 'absolute';
overlay.style.left = `${left}px`;
overlay.style.top = `${top}px`;
Recalculate after scrolling, resizing, content changes, or any style change that affects layout. A previously returned rectangle represents the geometry at the time you read it, not a permanently tracked point.
CSS zoom versus transform: scale()
CSS zoom and transform: scale() are not interchangeable. CSS zoom participates in layout, so surrounding flow and rendered geometry are affected. A scale transform visually scales an element without recalculating layout in the same way. Code that assumes one behavior can be wrong when the page uses the other.
.zoomed-panel {
zoom: 1.5;
}
.transformed-panel {
transform: scale(1.5);
transform-origin: top left;
}
In both cases, read the actual rendered rectangle rather than attempting to infer it from a CSS declaration. If a component can use either technique, test its positioning and hit testing with each implementation.
Why offsetWidth and clientWidth may disagree
Rectangle APIs include CSS zoom, while client properties, offset properties, and scrolling APIs do not include it in the same way. For example, rect.width can differ from element.offsetWidth when an ancestor or the element itself is zoomed. Do not mix those values as though they share a unit without an intentional conversion.
Element.currentCSSZoom reports the effective CSS zoom, including zoom values inherited through ancestors. An ancestor at 2 and another at 3 produce an effective value of 6. It is useful for diagnosing why unzoomed measurements differ, but it is not a multiplier for getBoundingClientRect() output.
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
const rect = element.getBoundingClientRect();
const effectiveZoom = element.currentCSSZoom;
console.log({
renderedWidth: rect.width,
effectiveZoom
});
MDN labels currentCSSZoom newly available since March 2026. Check your supported-browser matrix before relying on it; the rectangle itself remains the primary measurement.
Mobile pinch zoom and the visual viewport
On mobile, the layout viewport and the visual viewport can diverge. Pinch zoom, the on-screen keyboard, and browser interface changes can shrink or move the area the user currently sees. When the job is to follow that visible area, inspect window.visualViewport rather than treating CSS zoom as a visual-viewport multiplier.
function reportViewports() {
const layoutWidth = document.documentElement.clientWidth;
const layoutHeight = document.documentElement.clientHeight;
const visual = window.visualViewport;
console.log({
layoutWidth,
layoutHeight,
visualLeft: visual ? visual.offsetLeft : 0,
visualTop: visual ? visual.offsetTop : 0,
visualWidth: visual ? visual.width : layoutWidth,
visualHeight: visual ? visual.height : layoutHeight,
visualScale: visual ? visual.scale : 1
});
}
reportViewports();
window.visualViewport?.addEventListener('resize', reportViewports);
window.visualViewport?.addEventListener('scroll', reportViewports);
visualViewport.scale describes visual-viewport scaling; it is not a value to multiply into a DOMRect that already contains CSS zoom. Keep layout-viewport, visual-viewport, and document coordinates distinct.
Complete JavaScript helper
The following helper returns both common CSS-pixel spaces and makes the origin explicit.
export function measureElement(element) {
if (!(element instanceof Element)) {
throw new TypeError('Expected a DOM Element');
}
const rect = element.getBoundingClientRect();
return {
viewport: {
left: rect.left,
top: rect.top,
right: rect.right,
bottom: rect.bottom,
width: rect.width,
height: rect.height
},
document: {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY,
right: rect.right + window.scrollX,
bottom: rect.bottom + window.scrollY,
width: rect.width,
height: rect.height
},
cssZoom: 'currentCSSZoom' in element ? element.currentCSSZoom : undefined
};
}
const measured = measureElement(document.querySelector('.target'));
console.log(measured);
Keep the returned values as numbers until the final CSS assignment. Preserve fractional values unless your target API explicitly requires integers; rounding early can create visible one-pixel drift at non-integer zoom levels.
Rank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
Equivalent requests from cURL, Python, and Node.js
If you are implementing the browser code in a page, the JavaScript examples above are sufficient. For tooling that injects JavaScript into a browser, the same measurement logic can be evaluated after the page has reached the layout state you need. The following snippets show the core expression in each common environment.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
cURL with an automated browser endpoint
curl -X POST https://example.invalid/evaluate
-H 'Content-Type: application/json'
-d '{"script":"const r=document.querySelector(".target").getBoundingClientRect(); return {left:r.left,top:r.top,width:r.width,height:r.height};"}'
The endpoint, authentication, and request format are provider-specific; the important part is that the script runs in the page and reads the rectangle without applying another zoom multiplier.
Python
from selenium import webdriver
from selenium.webdriver.common.by import By
with webdriver.Chrome() as driver:
driver.get('https://example.com')
result = driver.execute_script("""
const r = document.querySelector('.target').getBoundingClientRect();
return {left: r.left, top: r.top, width: r.width, height: r.height};
""")
print(result)
Node.js
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
const result = await page.locator('.target').evaluate((element) => {
const r = element.getBoundingClientRect();
return { left: r.left, top: r.top, width: r.width, height: r.height };
});
console.log(result);
await browser.close();
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting coordinate mismatches
Everything is offset by the zoom factor
Cause: the rectangle was multiplied by zoom or currentCSSZoom. Fix: remove that multiplication and use rect.left, rect.top, and rect.width directly.
The overlay moves when the page scrolls
Cause: viewport coordinates were assigned to an absolutely positioned element, or document coordinates were assigned to a fixed element. Fix: pair viewport values with position: fixed; add scroll offsets for document-positioned elements.
Width differs from offsetWidth
Cause: those APIs do not report CSS zoom in the same way. Fix: choose one measurement family for the calculation, or document and intentionally convert between the two.
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 →Best Value
- 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
- Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
- Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
- HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
- What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
It works on desktop but not during mobile pinch zoom
Cause: the visual viewport has moved or resized independently of the layout viewport. Fix: read window.visualViewport and listen for its resize and scroll events when tracking what is visible.
Values are correct initially but stale later
Cause: layout, scrolling, fonts, or responsive styles changed after the measurement. Fix: measure after the relevant layout is ready and recalculate on the changes that can move the target. In animation loops, batch reads before writes to avoid unnecessary layout work.
A conversion to monitor pixels is inconsistent
Cause: “screen” was treated as a single universal coordinate space. Fix: specify whether the consumer expects viewport CSS pixels, document CSS pixels, browser-window coordinates, or physical display pixels, then test the platform-specific conversion.
Performance and reliability checklist
- Read the rectangle after the target exists and its styles have been applied.
- Use one coordinate origin throughout each calculation.
- Do not mix
getBoundingClientRect()with offset, client, or scroll measurements without accounting for their different zoom behavior. - Keep fractional CSS-pixel values until the final rendering or input boundary.
- Re-read after scroll, resize, responsive-layout changes, or content changes that affect geometry.
- For mobile visibility, observe the visual viewport separately from CSS zoom.
- Test any browser-window or hardware-pixel conversion on the exact browser and operating system you support.
Or skip the browser setup
If your actual goal is a clean image or PDF of a page rather than pointer automation at a DOM coordinate, ScreenshotNeo captures the page through one HTTP request. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
Free tools Windows power users keep installed
One-click scans. No signup required.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for all options, including full-page and element captures, device presets, custom CSS or JavaScript, waits, headers, cookies, blocking rules, PDFs, caching, asynchronous jobs, bulk capture, and signed links.
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
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}`);
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account to get started.
Frequently Asked Questions
Why can rectangle values contain decimals?
CSS layout permits fractional CSS-pixel positions and sizes, especially with non-integer zoom or responsive calculations. Keep the decimals for alignment and round only at an API boundary that requires integers.
Can a DOMRect be passed directly to an operating-system mouse API?
Usually not. A DOMRect is viewport-relative CSS geometry; native mouse APIs commonly require browser-window or physical-display coordinates. The conversion depends on the browser, window placement, display scale, and device state, so define and test that mapping separately.
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 glitchesQuick 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.

