79770098

Date: 2025-09-20 05:07:17
Score: 0.5
Natty:
Report link

12 years and noone has posted a simple, solid answer faithful to the original question. Granted, some other answers may work in your case if you don't really need to test whether the element is visible to the user; this gets into XY problem territory. Here's a summary of everything issue/quirk with the other answers:

Overall, I'd rate @FanaticPythoner's answer the winner at failing in more places than any other answer. His answer fails in iFrames, considers any element clipping a single pixel outside the viewport as hidden, badly misuses getComputedStyle without checking it upon ancestors, conflates parentNode with the nearest scroll ancestor scroll pane, seems not to understand z-index is relative to other elements (and would require extensive logic to reconcile absolute/fixed/sticky positioning of ancestors), checks all ancestors displays and opacities without considering visibility, and finishes with what seems to be half-baked attempted to only scan adjacent siblings for overlap (wtf?).

Here's a comprehensive solution that answers, simply, is the element visible to the user?

/** isVisibleToUser: tell whether the user can see a HTML element
 *    ele (required):      The DOM element to test.
 *    clip (default true): Consider any portion not scrolled into view.
 *                          as hidden. Use false to test if the element
 *                          can become visible if users scrolls to it.
 *    thres (default 0.5): What percentage must be visible for `true`.
 *    samp (default 2.14): Equispaced x/y samples. Decimal offsets it.
 *                         E.g. 2.14 calls elementFromPoint four times.
 */
function isVisibleToUser(ele, clip=true, thres=0.5, samp=2.14) {
    if ( ! checkVisibilityPolyfill(ele) ) return false;
    var t=+thres, s=+samp, B=ele.getBoundingClientRect();
    var O=ele.offsetParent, d=ele.ownerDocument, G=d.defaultView;
    var eT=B.top|0,eL=B.left|0,eB=B.bottom|0,eR=B.right|0,iW,iH;
        if (O) {B = O.getBoundingClientRect();
        var oT=B.top|0,oL=B.left|0,oB=B.bottom|0,oR=B.right|0;
        if (clip) iW=G.innerWidth|0,iH=G.innerHeight|0,
                      oT=oT<0?0:oT|0,oL=oL<0?0:oL|0,
                  oB=oB>iH?iH:oB|0,oR=oR>iW?iW:oR|0;
        var oW=oR-oL|0, oH=oB-oT|0;
    }else oT=0,oL=0,oR=oW=G.innerWidth|0,oB=oH=G.innerHeight|0;
    var eW=eR-eL|0, bX=(eL<oL?oL-eL|0:0) + (eR>oR?eR-oR|0:0)|0;
    var eH=eB-eT|0, bY=(eT<oT?oT-eT|0:0) + (eB>oB?eB-oB|0:0)|0;
    if(bX>(t*eW|0)||bY>(t*eH|0)||bX*bY>eW*eH*t)return false;
    var sW=eW/(s+1),sH=eH/(s+1),I=s|0,l=I*I*-t|0;
    for (var i=1; i<=I; i=i+1|0)
        for (var j=1; j<=I; j=j+1|0)
            if(d.elementFromPoint(.5+eL+sW*i|0,.5+eT+sH*j|0)
               !== ele) if ((l=l+1|0) >= 0) return false;
    return true; // all checks passed!
}
/** checkVisibilityPolyfill: fallback if checkVisibility unsupported
 */
function checkVisibilityPolyfill(ele) {
    if ("checkVisibility" in ele) return ele.checkVisibility();
    return !!ele.offsetParent||!!ele.offsetHeight||!!ele.offsetWidth;
}
Reasons:
  • Whitelisted phrase (-1): in your case
  • Long answer (-1):
  • Has code block (-0.5):
  • Ends in question mark (2):
  • User mentioned (1): @FanaticPythoner's
  • Looks like a comment (1):
  • High reputation (-1):
Posted by: Jack G