18

I have a following DOM structure

<body>
    <div>
       <table>
          <outerElement>
              <innerElement />  
          </outerElement>
       <table>
    </div>
</body>

DIV has its overflow set to auto so if table grows bigger - it scrolls within the DIV.

In this scenario why table.offsetParent returns the body while both table.parentNode and parentElement return the Div?

I need to calculate current position of the innerElement within the window, so I traverse from it up thru all parent elements, collecting their offsetTop and offsetLeft values. Up until the DIV offsetParent works fine and then it skips it directly to the body. The problem if there's scrolling involved at some point, I need to account for scrollTop and scrollLeft as well - like in the DIV in the above example. The problem is if I use offsetParent I never encounter the DIV as one of the parents.

UPDATE

This is part of the code that does the traversing:

while (oElem && getStyle(oElem, 'position') != 'absolute' && getStyle(oElem, 'position') != 'relative') { 
   curleft += oElem.offsetLeft;
   curtop += oElem.offsetTop;
   oElem = oElem.offsetParent;
}

where getStyle is a custom function that in this case retrieves the position style.

danronmoon
  • 3,814
  • 5
  • 34
  • 56
Yuriy Galanter
  • 38,833
  • 15
  • 69
  • 136

4 Answers4

49

offsetParent is the closest parent that has position:relative or position:absolute or the body of the page. parentNode is the direct parent, regardless of position.

kalley
  • 18,072
  • 2
  • 39
  • 36
  • Not exactly, I updated the question with more details. Technically I am trying to get position of `innerElement` to be exact, and many of its parents are static. – Yuriy Galanter Jul 31 '13 at 15:53
4

Using getBoudingClientRect() is really a great help (thanks Ally for the hint!).

If you still need the position relative to the upper left corner of the document, here's a helpful snippet:

if (node.getBoundingClientRect) {
    var rect = node.getBoundingClientRect();
    var sx = -(window.scrollX ? window.scrollX : window.pageXOffset);
    var sy = -(window.scrollY ? window.scrollY : window.pageYOffset);

    return {
        x: rect.left - sx,
        y: rect.top - sy
    }
}

Note: document.body.getBoundingClientRect() may return an unexpected value for topin Firefox under some circumstances. Therefore, the window scroll position is more robust.

For the client who do not yet support getBoundingClientRect(), we still must walk the offetParents and take care that every overflow: scroll (or auto) parent has position: relative.

BurninLeo
  • 4,240
  • 4
  • 39
  • 56
1

Stay clear of offsetParent, you'll have to add lots of hacks and checks to ensure you get it right.

Try using getBoundingClientRect instead.

Ally
  • 4,894
  • 8
  • 37
  • 45
  • 4
    offsetParent can be very useful and used properly you will not need "lots of hacks" – Mackelito May 22 '17 at 14:34
  • @Mackelito From what I remember it has a hard time with collapsing margins, its easier to work with `getBoundingClientRect`. – Ally Nov 16 '17 at 00:20
-2

offsetParent is essentially the parent in UI

parentNode is actually the parent in DATA/HTML

offsetParent is included to deprecate traditional parentNode

xosg
  • 89
  • 1
  • 6
  • welcome to stack, answer to an old question. but its answer need minimal of stacks answer, please read this https://stackoverflow.com/help/how-to-answer and edit you answer for give best feedback. – Amirhossein Apr 24 '20 at 03:54