检查元素在 DOM 中是不是可见

Posted

技术标签:

【中文标题】检查元素在 DOM 中是不是可见【英文标题】:Check if element is visible in DOM检查元素在 DOM 中是否可见 【发布时间】:2013-11-09 06:58:36 【问题描述】:

有什么方法可以检查一个元素在纯 JS(非 jQuery)中是否可见?

因此,例如,在此页面中:Performance Bikes,如果您将鼠标悬停在“交易”上(在顶部菜单上),则会出现一个交易窗口,但一开始并未显示。它在 html 中,但不可见。

那么,给定一个 DOM 元素,我如何检查它是否可见?我试过了:

window.getComputedStyle(my_element)['display']);

但它似乎不起作用。我想知道我应该检查哪些属性。我想到了:

display !== 'none'
visibility !== 'hidden'

还有什么我可能会错过的吗?

【问题讨论】:

不使用显示,它使用可见性,因此检查可见性(隐藏或可见)。例如:document.getElementById('snDealsPanel').style.visibility PSL。如果我想更一般地执行此操作,我应该检查哪些属性:可见性、显示...? 你可以用你自己的方式使其通用,但我的意思是它使用可见性检查元素。 这是我针对这个问题的代码(没有 jquery)***.com/a/22969337/2274995 链接已损坏,这使您的问题不易理解。请重新构图。 【参考方案1】:

根据this MDN documentation,元素的offsetParent 属性将返回null,只要它或其任何父元素通过显示样式属性隐藏。只要确保元素没有固定。如果您的页面上没有 position: fixed; 元素,则检查此内容的脚本可能如下所示:

// Where el is the DOM element you'd like to test for visibility
function isHidden(el) 
    return (el.offsetParent === null)

另一方面,如果您确实有可能在此搜索中被捕获的位置固定元素,您将遗憾地(并且慢慢地)必须使用window.getComputedStyle()。这种情况下的功能可能是:

// Where el is the DOM element you'd like to test for visibility
function isHidden(el) 
    var style = window.getComputedStyle(el);
    return (style.display === 'none')

选项 #2 可能更简单一些,因为它考虑了更多的边缘情况,但我敢打赌它也会慢很多,所以如果你必须多次重复这个操作,最好避免它。

【讨论】:

另外仅供参考,刚刚发现 el.offsetParent 不适用于 IE9 的非固定元素。反正看起来是这样。 (不过,对于 IE11 来说还可以。)毕竟getComputedStyle 也是如此。 唉! getComputedStyle 无法正常工作:plnkr.co/edit/6CSCA2fe4Gqt4jCBP2wu?p=preview 但是,offsetParent 也是如此 - 也许应该将两者结合使用? 对于 ie9+ie10,您可以检查 offsetParent = body 是否为不可见元素。 我看到 getComputedStyle(element).display 在祖先为 display:none 的某些元素(例如 TABLE 元素)中具有 table 的值,这实际上是无用的。 只是window.getComputedStyle方法的一个注释,它返回一个live CSSStyleDeclaration对象。所以你只需要抓取一次样式,如果你必须执行多次检查,则可以重新检查对象。【参考方案2】:

所有其他解决方案都因我的某些情况而崩溃..

在以下位置查看获奖答案:

http://plnkr.co/edit/6CSCA2fe4Gqt4jCBP2wu?p=preview

最终,我认为最好的解决方案是$(elem).is(':visible') - 但是,这不是纯 javascript。它是 jquery ..

所以我偷看了他们的来源并找到了我想要的东西

jQuery.expr.filters.visible = function( elem ) 
    return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
;

这是来源:https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js

【讨论】:

这将为带有visibility:hidden的元素返回true @YuvalA.:是的,因为该元素仍然可见。将元素设置为visibility:hidden 不再显示内容,但仍采用元素的宽度和高度! @Michael 您可以轻松浏览 jQuery 代码,如果您使用的是任何现代 IDE(如果没有,请尝试一下),您可以在使用 jQuery 或任何其他库时跳转到正确的代码部分。您可以在浏览开源项目的代码库时学到很多东西。 OP 要求没有 jQuery 的解决方案 对于正在寻找同样适用于visibility:hidden 的版本的任何人,将&& window.getComputedStyle(elem).visibility !== "hidden" 添加到此返回行的末尾似乎有效【参考方案3】:

如果你有兴趣被用户看到:

function isVisible(elem) 
    if (!(elem instanceof Element)) throw Error('DomUtil: elem is not an element.');
    const style = getComputedStyle(elem);
    if (style.display === 'none') return false;
    if (style.visibility !== 'visible') return false;
    if (style.opacity < 0.1) return false;
    if (elem.offsetWidth + elem.offsetHeight + elem.getBoundingClientRect().height +
        elem.getBoundingClientRect().width === 0) 
        return false;
    
    const elemCenter   = 
        x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
        y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
    ;
    if (elemCenter.x < 0) return false;
    if (elemCenter.x > (document.documentElement.clientWidth || window.innerWidth)) return false;
    if (elemCenter.y < 0) return false;
    if (elemCenter.y > (document.documentElement.clientHeight || window.innerHeight)) return false;
    let pointContainer = document.elementFromPoint(elemCenter.x, elemCenter.y);
    do 
        if (pointContainer === elem) return true;
     while (pointContainer = pointContainer.parentNode);
    return false;

测试(使用mocha 术语):

describe.only('visibility', function () 
    let div, visible, notVisible, inViewport, leftOfViewport, rightOfViewport, aboveViewport,
        belowViewport, notDisplayed, zeroOpacity, zIndex1, zIndex2;
    before(() => 
        div = document.createElement('div');
        document.querySelector('body').appendChild(div);
        div.appendChild(visible = document.createElement('div'));
        visible.style       = 'border: 1px solid black; margin: 5px; display: inline-block;';
        visible.textContent = 'visible';
        div.appendChild(inViewport = visible.cloneNode(false));
        inViewport.textContent = 'inViewport';
        div.appendChild(notDisplayed = visible.cloneNode(false));
        notDisplayed.style.display = 'none';
        notDisplayed.textContent   = 'notDisplayed';
        div.appendChild(notVisible = visible.cloneNode(false));
        notVisible.style.visibility = 'hidden';
        notVisible.textContent      = 'notVisible';
        div.appendChild(leftOfViewport = visible.cloneNode(false));
        leftOfViewport.style.position = 'absolute';
        leftOfViewport.style.right = '100000px';
        leftOfViewport.textContent = 'leftOfViewport';
        div.appendChild(rightOfViewport = leftOfViewport.cloneNode(false));
        rightOfViewport.style.right       = '0';
        rightOfViewport.style.left       = '100000px';
        rightOfViewport.textContent = 'rightOfViewport';
        div.appendChild(aboveViewport = leftOfViewport.cloneNode(false));
        aboveViewport.style.right       = '0';
        aboveViewport.style.bottom       = '100000px';
        aboveViewport.textContent = 'aboveViewport';
        div.appendChild(belowViewport = leftOfViewport.cloneNode(false));
        belowViewport.style.right       = '0';
        belowViewport.style.top       = '100000px';
        belowViewport.textContent = 'belowViewport';
        div.appendChild(zeroOpacity = visible.cloneNode(false));
        zeroOpacity.textContent   = 'zeroOpacity';
        zeroOpacity.style.opacity = '0';
        div.appendChild(zIndex1 = visible.cloneNode(false));
        zIndex1.textContent = 'zIndex1';
        zIndex1.style.position = 'absolute';
        zIndex1.style.left = zIndex1.style.top = zIndex1.style.width = zIndex1.style.height = '100px';
        zIndex1.style.zIndex = '1';
        div.appendChild(zIndex2 = zIndex1.cloneNode(false));
        zIndex2.textContent = 'zIndex2';
        zIndex2.style.left = zIndex2.style.top = '90px';
        zIndex2.style.width = zIndex2.style.height = '120px';
        zIndex2.style.backgroundColor = 'red';
        zIndex2.style.zIndex = '2';
    );
    after(() => 
        div.parentNode.removeChild(div);
    );
    it('isVisible = true', () => 
        expect(isVisible(div)).to.be.true;
        expect(isVisible(visible)).to.be.true;
        expect(isVisible(inViewport)).to.be.true;
        expect(isVisible(zIndex2)).to.be.true;
    );
    it('isVisible = false', () => 
        expect(isVisible(notDisplayed)).to.be.false;
        expect(isVisible(notVisible)).to.be.false;
        expect(isVisible(document.createElement('div'))).to.be.false;
        expect(isVisible(zIndex1)).to.be.false;
        expect(isVisible(zeroOpacity)).to.be.false;
        expect(isVisible(leftOfViewport)).to.be.false;
        expect(isVisible(rightOfViewport)).to.be.false;
        expect(isVisible(aboveViewport)).to.be.false;
        expect(isVisible(belowViewport)).to.be.false;
    );
);

【讨论】:

如果元素位于视口之外的边缘情况,可以通过“if (!pointContainer) return false;”捕获检查第一个点容器 如果您想检查用户是否可以看到它,您必须使用scrollIntoView 对吧?!这是相当昂贵的。还有其他聪明的方法吗? 重叠元素(准确地说:所有重叠元素)的不透明度 救命稻草。 js就是这样的……语言【参考方案4】:

使用与 jQuery 相同的代码:

jQuery.expr.pseudos.visible = function( elem ) 
    return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
;

所以,在一个函数中:

function isVisible(e) 
    return !!( e.offsetWidth || e.offsetHeight || e.getClientRects().length );

在我的 Win/IE10、Linux/Firefox.45、Linux/Chrome.52...中运行起来就像一个魅力...

非常感谢没有 jQuery 的 jQuery!

【讨论】:

不错,但不包括被溢出隐藏的元素。 很好,但是为什么! (双重否定)? 强制结果为布尔值。由于e.offsetWidth 是一个整数,如果e.offsetWidth 大于零(元素可见),!e.offsetWidth 将返回false。因此,如果e.offsetWidth 大于零,则在!!e.offsetWidth 中添加另一个! 将返回true。这是return e.offsetWidth &gt; 0 ? true : false 或显然是return e.offsetWidth &gt; 0 的简写。【参考方案5】:

这可能会有所帮助: 通过将元素定位在最左边的位置来隐藏元素,然后检查 offsetLeft 属性。如果你想使用 jQuery,你可以简单地检查 :visible 选择器并获取元素的可见性状态。

HTML:

<div id="myDiv">Hello</div>

CSS:

<!-- for javaScript-->
#myDiv
   position:absolute;
   left : -2000px;


<!-- for jQuery -->
#myDiv
    visibility:hidden;

javaScript:

var myStyle = document.getElementById("myDiv").offsetLeft;

if(myStyle < 0)
     alert("Div is hidden!!");

jQuery :

if(  $("#MyElement").is(":visible") == true )
  
     alert("Div is visible!!");        

jsFiddle

【讨论】:

OP 请求非 jQuery 答案。 我猜它后来被编辑了。当我回答时,线程中没有提到它。 @StephenQuan,我已经用 jQuery 和 javaScript 解决方案更新了答案。 对于 jQuery 示例,警报不应该说“Div 可见吗?” 我不想仅仅因为它的 offsetLeft 小于 0 就得出一个元素完全隐藏的结论:如果它只是小于 0 的一小部分像素并且它的右侧部分是可见的怎么办? (我同意这似乎是一个愚蠢的设计,但这些天你永远不会知道网页设计师。)最好将宽度添加到 offsetLeft 并查看结果是否仍然小于 0。以防万一。【参考方案6】:

接受的答案对我不起作用。

2020 年细分。

    (elem.offsetParent !== null) 方法在 Firefox 中可以正常工作,但在 Chrome 中则不行。在 Chrome 中,position: fixed 也会使offsetParent 返回null,即使是在页面中可见的元素。

    用户 Phrogz 对具有不同属性的元素进行了大型测试(2,304 个 div)来证明该问题。 https://***.com/a/11639664/4481831 。 使用多个浏览器运行它以查看差异。

    演示:

    //different results in Chrome and Firefox
    console.log(document.querySelector('#hidden1').offsetParent); //null Chrome & Firefox
    console.log(document.querySelector('#fixed1').offsetParent); //null in Chrome, not null in Firefox
        <div id="hidden1" style="display:none;"></div>
        <div id="fixed1" style="position:fixed;"></div>

    (getComputedStyle(elem).display !== 'none') 不起作用,因为该元素可能是不可见的,因为其中一个父显示属性设置为 none,getComputedStyle 不会捕捉到这一点。

    演示:

    var child1 = document.querySelector('#child1');
    console.log(getComputedStyle(child1).display);
    //child will show "block" instead of "none"
    <div id="parent1" style="display:none;">
      <div id="child1" style="display:block"></div>
    </div>

    (elem.clientHeight !== 0)。此方法不受position: fixed 的影响,它还会检查元素父级是否不可见。但是它对于没有css布局的简单元素有问题,see more here

    演示:

    console.log(document.querySelector('#div1').clientHeight); //not zero
    console.log(document.querySelector('#span1').clientHeight); //zero
    <div id="div1">test1 div</div>
    <span id="span1">test2 span</span>

    (elem.getClientRects().length !== 0) 似乎可以解决前面 3 种方法的问题。但是,使用 CSS 技巧(除 display: none 以外)隐藏在页面中的元素存在问题。

    演示

    console.log(document.querySelector('#notvisible1').getClientRects().length);
    console.log(document.querySelector('#notvisible1').clientHeight);
    console.log(document.querySelector('#notvisible2').getClientRects().length);
    console.log(document.querySelector('#notvisible2').clientHeight);
    console.log(document.querySelector('#notvisible3').getClientRects().length);
    console.log(document.querySelector('#notvisible3').clientHeight);
    <div id="notvisible1" style="height:0; overflow:hidden; background-color:red;">not visible 1</div>
    
    <div id="notvisible2" style="visibility:hidden; background-color:yellow;">not visible 2</div>
    
    <div id="notvisible3" style="opacity:0; background-color:blue;">not visible 3</div>

结论。

所以我向您展示的是,没有一种方法是完美的。要进行正确的可见性检查,您必须结合使用最后 3 种方法。

【讨论】:

在 Chrome 88.0.4324.104 中,第一个结果给我 null,null。【参考方案7】:

结合上面的几个答案:

function isVisible (ele) 
    var style = window.getComputedStyle(ele);
    return  style.width !== "0" &&
    style.height !== "0" &&
    style.opacity !== "0" &&
    style.display!=='none' &&
    style.visibility!== 'hidden';

就像 AlexZ 所说,如果您更具体地知道要查找的内容,这可能会比您的其他一些选项慢,但这应该可以捕捉到隐藏元素的所有主要方式。

但是,这也取决于对您来说什么是可见的。例如,可以将 div 的高度设置为 0px,但内容仍然可见,具体取决于溢出属性。或者,可以将 div 的内容设置为与背景相同的颜色,以便用户看不到它,但仍会在页面上呈现。或者一个 div 可以移出屏幕或隐藏在其他 div 后面,或者它的内容可能不可见但边框仍然可见。在某种程度上,“可见”是一个主观术语。

【讨论】:

很好,但是 style.opacity、style.height 和 style.width 返回一个字符串,所以它不能与 !== 一起使用 通过样式隐藏元素的另一种方式是它的颜色可以与背景颜色匹配,或者它的 z-index 可能低于其他元素。 添加display:none 会很棒。一个合适的解决方案!【参考方案8】:

与AlexZ's getComputedStyle() solution 相比,我有一个性能更高的解决方案,当一个人具有位置“固定”元素时,如果有人愿意忽略一些边缘情况(检查 cmets):

function isVisible(el) 
    /* offsetParent would be null if display 'none' is set.
       However Chrome, IE and MS Edge returns offsetParent as null for elements
       with CSS position 'fixed'. So check whether the dimensions are zero.

       This check would be inaccurate if position is 'fixed' AND dimensions were
       intentionally set to zero. But..it is good enough for most cases.*/
    if (!el.offsetParent && el.offsetWidth === 0 && el.offsetHeight === 0) 
        return false;
    
    return true;

旁注:严格来说,需要先定义“可见性”。就我而言,我正在考虑一个元素可见,只要我可以在其上运行所有 DOM 方法/属性而不会出现问题(即使不透明度为 0 或 CSS 可见性属性为“隐藏”等)。

【讨论】:

【参考方案9】:

如果元素是常规可见的(显示:块和可见性:可见),但某些父容器是隐藏的,那么我们可以使用 clientWidthclientHeight 进行检查。

function isVisible (ele) 
  return  ele.clientWidth !== 0 &&
    ele.clientHeight !== 0 &&
    (ele.style.opacity !== '' ? parseFloat(ele.style.opacity) > 0 : true);

Plunker (click here)

【讨论】:

ele.style.visibility !== 'hidden' 在这里是多余的。在这种情况下,clientWidth 和 clientHeight 将为 0。 不透明度检查需要强制为数字,因为style 值都是字符串。例如,parseFloat(ele.style.opacity) &lt; 0.1【参考方案10】:

所以我找到的是最可行的方法:

function visible(elm) 
  if(!elm.offsetHeight && !elm.offsetWidth)  return false; 
  if(getComputedStyle(elm).visibility === 'hidden')  return false; 
  return true;

这是建立在这些事实之上的:

display: none 元素(即使是嵌套元素)没有宽度和高度。 visiblityhidden 即使对于嵌套元素。

因此无需测试offsetParent 或在DOM 树中循环来测试哪个父级拥有visibility: hidden。这在 IE 9 中也应该可以工作。

您可能会争论opacity: 0 和折叠的元素(有宽度但没有高度 - 反之亦然)是否也不是真正可见的。但话又说回来,它们并不是隐藏的。

【讨论】:

【参考方案11】:

对 ohad navon 的回答稍加补充。

如果元素的中心属于另一个元素,我们将找不到它。

所以要确保元素的其中一个点被发现是可见的

function isElementVisible(elem) 
    if (!(elem instanceof Element)) throw Error('DomUtil: elem is not an element.');
    const style = getComputedStyle(elem);
    if (style.display === 'none') return false;
    if (style.visibility !== 'visible') return false;
    if (style.opacity === 0) return false;
    if (elem.offsetWidth + elem.offsetHeight + elem.getBoundingClientRect().height +
        elem.getBoundingClientRect().width === 0) 
        return false;
    
    var elementPoints = 
        'center': 
            x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
            y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
        ,
        'top-left': 
            x: elem.getBoundingClientRect().left,
            y: elem.getBoundingClientRect().top
        ,
        'top-right': 
            x: elem.getBoundingClientRect().right,
            y: elem.getBoundingClientRect().top
        ,
        'bottom-left': 
            x: elem.getBoundingClientRect().left,
            y: elem.getBoundingClientRect().bottom
        ,
        'bottom-right': 
            x: elem.getBoundingClientRect().right,
            y: elem.getBoundingClientRect().bottom
        
    

    for(index in elementPoints) 
        var point = elementPoints[index];
        if (point.x < 0) return false;
        if (point.x > (document.documentElement.clientWidth || window.innerWidth)) return false;
        if (point.y < 0) return false;
        if (point.y > (document.documentElement.clientHeight || window.innerHeight)) return false;
        let pointContainer = document.elementFromPoint(point.x, point.y);
        if (pointContainer !== null) 
            do 
                if (pointContainer === elem) return true;
             while (pointContainer = pointContainer.parentNode);
        
    
    return false;

【讨论】:

【参考方案12】:

如果我们只是收集检测可见性的基本方法,请不要忘记:

opacity > 0.01; // probably more like .1 to actually be visible, but YMMV

以及如何获取属性:

element.getAttribute(attributename);

所以,在你的例子中:

document.getElementById('snDealsPanel').getAttribute('visibility');

但是什么?它在这里不起作用。仔细观察,您会发现更新可见性不是作为元素的属性,而是使用style 属性。这是尝试做你正在做的事情的许多问题之一。其中包括:你不能保证在一个元素中确实有东西可以看到,仅仅因为它的可见性、显示和不透明度都有正确的值。它仍然可能缺少内容,或者可能缺少高度和宽度。另一个物体可能会掩盖它。有关更多详细信息,快速 Google 搜索会显示this,甚至包括一个库来尝试解决问题。 (YMMV)

查看以下内容,这些内容可能与此问题重复,并提供出色的答案,包括来自强大的 John Resig 的一些见解。但是,您的具体用例与标准用例略有不同,因此我将避免标记:

How to tell if a DOM element is visible in the current viewport? How to check if an element is really visible with javascript?

(编辑:OP 说他正在抓取页面,而不是创建它们,因此以下内容不适用) 更好的选择?将元素的可见性绑定到模型属性并始终使可见性取决于该模型,就像 Angular 对 ng-show 所做的那样。你可以使用任何你想要的工具来做到这一点:Angular、纯 JS 等等。更好的是,您可以随时间更改 DOM 实现,但您将始终能够从模型而不是 DOM 中读取状态。从 DOM 中读取你的真相是不好的。而且慢。检查模型要好得多,并信任您的实现以确保 DOM 状态反映模型。 (并使用自动化测试来确认该假设。)

【讨论】:

我正在解析网站,这不适合我自己的网站... :)【参考方案13】:

仅供参考,应注意getBoundingClientRect()在某些情况下可以工作。

例如,使用display: none 简单检查元素是否隐藏可能看起来像这样:

var box = element.getBoundingClientRect();
var visible = box.width && box.height;

这也很方便,因为它还涵盖了零宽度、零高度和position: fixed 的情况。但是,它不会报告使用opacity: 0visibility: hidden 隐藏的元素(但offsetParent 也不会报告)。

【讨论】:

对我来说最好的答案...简单而有效。 3年后没有一个赞成票!继续展示“大众智慧”的价值。我的版本:var isVisible = el =&gt; (r =&gt; r.width &amp;&amp; r.height)(el.getBoundingClientRect());。然后我可以通过以下方式过滤元素数组:$$(sel).filter(isVisible). 我发现它是最简单的解决方案developer.mozilla.org/en-US/docs/Web/API/Element/… 这在用户可见时不起作用....如果您滚动离开,它将保持真实 @RayFoss 你明白“可见”有多种定义,对吧? :) 只是为了说清楚“在 DOM 中可见”或“在屏幕上可见”或“在视口中可见”或“在带有滚动条的容器内可见”——所有这些都意味着不同的事物和实现。此外,元素的可见性如何?它是否仅在其所有像素都被渲染时才可见? (变换呢?)或者,如果只有它的“概念透明”填充当前在屏幕上,它是否可见?总而言之,我认为定义很大程度上取决于您的具体用例。【参考方案14】:

改进@Guy Messika 的answer above,如果中心点 X 小于 0,则中断并返回 false,因为元素右侧可能会进入视图。这是一个修复:

private isVisible(elem) 
    const style = getComputedStyle(elem);

    if (style.display === 'none') return false;
    if (style.visibility !== 'visible') return false;
    if ((style.opacity as any) === 0) return false;

    if (
        elem.offsetWidth +
        elem.offsetHeight +
        elem.getBoundingClientRect().height +
        elem.getBoundingClientRect().width === 0
    ) return false;

    const elementPoints = 
        center: 
            x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
            y: elem.getBoundingClientRect().top + elem.offsetHeight / 2,
        ,
        topLeft: 
            x: elem.getBoundingClientRect().left,
            y: elem.getBoundingClientRect().top,
        ,
        topRight: 
            x: elem.getBoundingClientRect().right,
            y: elem.getBoundingClientRect().top,
        ,
        bottomLeft: 
            x: elem.getBoundingClientRect().left,
            y: elem.getBoundingClientRect().bottom,
        ,
        bottomRight: 
            x: elem.getBoundingClientRect().right,
            y: elem.getBoundingClientRect().bottom,
        ,
    ;

    const docWidth = document.documentElement.clientWidth || window.innerWidth;
    const docHeight = document.documentElement.clientHeight || window.innerHeight;

    if (elementPoints.topLeft.x > docWidth) return false;
    if (elementPoints.topLeft.y > docHeight) return false;
    if (elementPoints.bottomRight.x < 0) return false;
    if (elementPoints.bottomRight.y < 0) return false;

    for (let index in elementPoints) 
        const point = elementPoints[index];
        let pointContainer = document.elementFromPoint(point.x, point.y);
        if (pointContainer !== null) 
            do 
                if (pointContainer === elem) return true;
             while (pointContainer = pointContainer.parentNode);
        
    
    return false;

【讨论】:

【参考方案15】:

http://code.jquery.com/jquery-1.11.1.js 的 jQuery 代码有一个 isHidden 参数

var isHidden = function( elem, el ) 
    // isHidden might be called from jQuery#filter function;
    // in that case, element will be second argument
    elem = el || elem;
    return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
;

所以看起来有一个与所有者文档相关的额外检查

我想知道这是否真的抓住了以下情况:

    基于 zIndex 隐藏在其他元素后面的元素 完全透明的元素使它们不可见 元素位于屏幕外(即左侧:-1000px) 可见性元素:隐藏 显示元素:无 没有可见文本或子元素的元素 高度或宽度设置为 0 的元素

【讨论】:

【参考方案16】:

为了详细说明每个人的精彩答案,这里是 Mozilla Fathom 项目中使用的the implementation:

/**
 * Yield an element and each of its ancestors.
 */
export function *ancestors(element) 
    yield element;
    let parent;
    while ((parent = element.parentNode) !== null && parent.nodeType === parent.ELEMENT_NODE) 
        yield parent;
        element = parent;
    


/**
 * Return whether an element is practically visible, considering things like 0
 * size or opacity, ``visibility: hidden`` and ``overflow: hidden``.
 *
 * Merely being scrolled off the page in either horizontally or vertically
 * doesn't count as invisible; the result of this function is meant to be
 * independent of viewport size.
 *
 * @throws Error The element (or perhaps one of its ancestors) is not in a
 *     window, so we can't find the `getComputedStyle()` routine to call. That
 *     routine is the source of most of the information we use, so you should
 *     pick a different strategy for non-window contexts.
 */
export function isVisible(fnodeOrElement) 
    // This could be 5x more efficient if https://github.com/w3c/csswg-drafts/issues/4122 happens.
    const element = toDomElement(fnodeOrElement);
    const elementWindow = windowForElement(element);
    const elementRect = element.getBoundingClientRect();
    const elementStyle = elementWindow.getComputedStyle(element);
    // Alternative to reading ``display: none`` due to Bug 1381071.
    if (elementRect.width === 0 && elementRect.height === 0 && elementStyle.overflow !== 'hidden') 
        return false;
    
    if (elementStyle.visibility === 'hidden') 
        return false;
    
    // Check if the element is irrevocably off-screen:
    if (elementRect.x + elementRect.width < 0 ||
        elementRect.y + elementRect.height < 0
    ) 
        return false;
    
    for (const ancestor of ancestors(element)) 
        const isElement = ancestor === element;
        const style = isElement ? elementStyle : elementWindow.getComputedStyle(ancestor);
        if (style.opacity === '0') 
            return false;
        
        if (style.display === 'contents') 
            // ``display: contents`` elements have no box themselves, but children are
            // still rendered.
            continue;
        
        const rect = isElement ? elementRect : ancestor.getBoundingClientRect();
        if ((rect.width === 0 || rect.height === 0) && elementStyle.overflow === 'hidden') 
            // Zero-sized ancestors don’t make descendants hidden unless the descendant
            // has ``overflow: hidden``.
            return false;
        
    
    return true;

它检查每个父母的不透明度、显示和矩形。

【讨论】:

【参考方案17】:
let element = document.getElementById('element');
let rect = element.getBoundingClientRect();

if(rect.top == 0 && 
  rect.bottom == 0 && 
  rect.left == 0 && 
  rect.right == 0 && 
  rect.width == 0 && 
  rect.height == 0 && 
  rect.x == 0 && 
  rect.y == 0)

  alert('hidden');

else

  alert('visible');

【讨论】:

请不要发布仅代码的答案。对于未来的读者来说,看到解释为什么这回答了这个问题会更有趣。此外,当您回答一个已经很好回答的老问题时,您需要进一步解释。【参考方案18】:

这是我编写的代码,用于查找几个相似元素中唯一可见的元素,并在不使用 jQuery 的情况下返回其“类”属性的值:

  // Build a NodeList:
  var nl = document.querySelectorAll('.myCssSelector');

  // convert it to array:
  var myArray = [];for(var i = nl.length; i--; myArray.unshift(nl[i]));

  // now find the visible (= with offsetWidth more than 0) item:
  for (i =0; i < myArray.length; i++)
    var curEl = myArray[i];
    if (curEl.offsetWidth !== 0)
      return curEl.getAttribute("class");
    
  

【讨论】:

【参考方案19】:

这就是我所做的:

HTML & CSS:默认隐藏元素

<html>
<body>

<button onclick="myFunction()">Click Me</button>

<p id="demo" style ="visibility: hidden;">Hello World</p> 

</body>
</html> 

JavaScript:添加了检查可见性是否隐藏的代码:

<script>
function myFunction() 
   if ( document.getElementById("demo").style.visibility === "hidden")
   document.getElementById("demo").style.visibility = "visible";
   
   else document.getElementById("demo").style.visibility = "hidden";

</script>

【讨论】:

【参考方案20】:

2021解决方案

根据MSD docs,交互观察者异步观察目标元素与祖先元素或***文档视口的交集的变化。这意味着每次元素与视口相交时,交互观察者都会触发。

截至2021年,目前所有浏览器都支持交互观察器,除了IE。

实施

const el = document.getElementById("your-target-element");
const observer = new IntersectionObserver((entries) => 
    if(entries[0].isIntersecting)
         // el is visible
     else 
         // el is not visible
    
);
observer.observe(el);

【讨论】:

【参考方案21】:

我正在使用这个。适合我。

var element= document.getElementById('elementId');

if (element.style.display == "block")

<!-- element is visible -->

 else 

<!-- element is hidden-->


【讨论】:

【参考方案22】:

这是一种为所有 css 属性(包括可见性)确定它的方法:

html:

<div id="element">div content</div>

css:

#element

visibility:hidden;

javascript:

var element = document.getElementById('element');
 if(element.style.visibility == 'hidden')
alert('hidden');

else

alert('visible');

它适用于任何 css 属性,并且用途广泛且可靠。

【讨论】:

[element.style.display == "none"] 对我有用

以上是关于检查元素在 DOM 中是不是可见的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript JavaScript DOM元素可见性检查器

检查DOM元素是否完全可见

JavaScript DOM元素可见性检查器

检查元素是不是对用户真正可见

Jquery检查元素在视口中是不是可见[重复]

有没有办法只使用javascript检查一个元素在视口中是不是可见? [复制]