JavaScript getBoundingClientRect() changes while scrolling

前端 未结 2 1348
攒了一身酷
攒了一身酷 2020-12-04 08:42

I want to have the exact distance between the Y-coordinate of an element an the Y-value=0, which I consider as the top of the document.

myElement.getBounding         


        
2条回答
  •  一整个雨季
    2020-12-04 09:16

    getBoundingClientRect needs a bit more care to avoid bugs in scrollY/pageYOffset:

    function absolutePosition(el) {
        var
            found,
            left = 0,
            top = 0,
            width = 0,
            height = 0,
            offsetBase = absolutePosition.offsetBase;
        if (!offsetBase && document.body) {
            offsetBase = absolutePosition.offsetBase = document.createElement('div');
            offsetBase.style.cssText = 'position:absolute;left:0;top:0';
            document.body.appendChild(offsetBase);
        }
        if (el && el.ownerDocument === document && 'getBoundingClientRect' in el && offsetBase) {
            var boundingRect = el.getBoundingClientRect();
            var baseRect = offsetBase.getBoundingClientRect();
            found = true;
            left = boundingRect.left - baseRect.left;
            top = boundingRect.top - baseRect.top;
            width = boundingRect.right - boundingRect.left;
            height = boundingRect.bottom - boundingRect.top;
        }
        return {
            found: found,
            left: left,
            top: top,
            width: width,
            height: height,
            right: left + width,
            bottom: top + height
        };
    }
    

    The bugs to avoid are:

    • scrolling in Android Chrome since Chrome Mobile 43 has wrong values for scrollY/pageYOffset (especially when the keyboard is showing and you scroll).

    • Pinch-zoom in Microsoft IE or Edge causes wrong values for scrollY/pageYOffset.

    • Some (obsolete) browsers don't have a height/width e.g. IE8

    Edit: The above code can be simplified a lot by just using document.body.getBoundingClientRect() instead of adding a div - I haven't tried it though so I am leaving my answer as it stands. Also the body needs margin:0 (reset.css usually does this). This answer simplifies the code down a lot, while still avoiding the bugs in jQuery.offset()!

    Edit 2: Chrome 61 introduced window.visualViewport to give correct values for the actual viewport which is probably another way to fix issues; but beware that Android Chrome 66 was still buggy if Settings -> Accessability -> Force enable zoom was ticked (bugs with orientation change, focused inputs, absolutely positioned popup wider than viewport).

提交回复
热议问题