Skip to content
All articles
JavaScript reference

offsetParent in JavaScript: Examples and Null Cases

Understand element.offsetParent, why it can be null, and when to use offsetTop or getBoundingClientRect. Includes a working positioned-container example.

5 min read - Updated 2026-09-05

element.offsetParent is a layout reference, not necessarily the element’s DOM parent. offsetTop and offsetLeft use that reference when reporting layout offsets. If you need the element’s current visual position in the viewport, getBoundingClientRect() is usually the more direct API.

A positioned-container example

The child below is absolutely positioned inside a relatively positioned container. With no margins or borders to complicate the example, offsetParent is the container, offsetLeft is 24, and offsetTop is 40. The child’s immediate DOM parent happens to be the same element here, but an unpositioned wrapper would not necessarily become the offset parent.

<div id="container" style="position: relative; width: 240px; height: 160px;">
  <div id="child" style="position: absolute; left: 24px; top: 40px;">Hello</div>
</div>

<script>
  const child = document.querySelector('#child');
  console.log(child.offsetParent.id); // "container"
  console.log(child.offsetLeft);      // 24
  console.log(child.offsetTop);       // 40
</script>

A nearby ancestor with non-static positioning is a common offset parent.

Table-related layout and differences in effective CSS zoom are additional cases; “nearest positioned ancestor” is a useful shortcut, not the entire rule.

Do not confuse offsetParent with parentElement or assume it is always present.

Why offsetParent can be null

An element without a CSS layout box has no offset parent. This includes an element hidden with display: none and a descendant of such an element. Root/body elements and viewport-fixed elements are other common null cases. Fixed positioning and browser differences deserve extra care: null is not a complete visibility test.

const element = document.querySelector('#child');
if (element instanceof HTMLElement) {
  const parent = element.offsetParent;
  if (parent === null) {
    console.log('No offset parent; inspect layout and positioning.');
  } else {
    console.log(parent, element.offsetLeft, element.offsetTop);
  }
}

Check display: none on ancestors as well as on the element itself.

Detached elements usually have no rendered layout box.

A viewport-fixed element commonly returns null; positioned containing blocks and browser behavior can affect the result.

visibility: hidden and opacity: 0 do not remove the layout box, so they need not produce null.

Choose the coordinate system you actually need

offsetTop and offsetLeft describe layout offsets relative to the offset parent’s padding edge. getBoundingClientRect() reports the element’s bounding rectangle relative to the viewport, including visual transforms, and its values can contain fractions. Scrolling changes those viewport-relative coordinates.

const element = document.querySelector('#child');
if (element) {
  const rect = element.getBoundingClientRect();
  console.log({ viewportX: rect.left, viewportY: rect.top });

  // Coordinates relative to the top-level document at this moment:
  console.log({ documentX: rect.left + window.scrollX,
                documentY: rect.top + window.scrollY });
}
Choose the coordinate system you actually need
APICoordinate systemUseful for
parentElementDOM treeFinding the immediate parent element
offsetParent + offsetTop/offsetLeftLayout offsets relative to the offset parentUnderstanding positioned-container layout
getBoundingClientRect()Current viewport-relative visual boundsComparing element bounds with the viewport or another rectangle

Debug coordinates across responsive layouts

A media query can change position, display, or the ancestor structure used by the layout. Inspect the element and its offset parent at both widths. If a transform is involved, compare layout offsets with the visual rectangle instead of expecting them to be equal.

Log the offset parent, computed position, and visual rectangle together.

Check whether the element is hidden at the failing breakpoint.

Account for container borders, margins, nested scrolling, and transforms before subtracting coordinates.

Use Sizzy to compare widths and console output; test browser-specific behavior in the actual target engine.

Practical checklist

Decide whether you need DOM ancestry, layout offsets, or viewport coordinates.

Handle a null offsetParent without treating it as a complete visibility test.

Check ancestor display and positioning at the failing width.

Use getBoundingClientRect() for transformed visual bounds.

Frequently asked questions

Is offsetParent the same as parentElement?

No. parentElement is the immediate DOM parent. offsetParent is a layout reference, often a positioned ancestor, and may skip wrappers or return null.

Why does offsetParent return null for a visible element?

Viewport-fixed elements can return null even while visible. The html and body elements also have special behavior. Do not use offsetParent alone as a visibility check.

Does offsetTop include CSS transforms?

offsetTop describes layout offsets, not the final transformed visual position. Use getBoundingClientRect() when you need the element’s rendered viewport-relative bounds.

Sources and further reading

Related guides