web-dev-qa-db-ja.com

要素がDOMに表示されるかどうかを確認してください

要素がピュアJSで表示されているかどうかを確認できる方法はありますか(jQueryなし)。

だから、例えば、このページでは: パフォーマンスバイク 、あなたが(トップメニューの)Dealsの上にマウスを持っていくと、お得な情報のウィンドウが表示されますが、最初は表示されませんでした。 HTMLにありますが、表示されません。

それで、DOM要素が与えられたとき、それが見えるかどうかをどうやって確認することができますか?私は試した:

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

しかし、それはうまくいっていないようです。どの属性をチェックすればいいのでしょうか。それは私の頭に浮かぶ:

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

私が行方不明になっているかもしれない他の人?

279
Hommer Smith

このMDNドキュメント によると、要素またはその親のいずれかが表示スタイルプロパティによって隠されているときはいつでも、要素のoffsetParentプロパティはnullを返します。要素が固定されていないことを確認してください。これをチェックするスクリプトは、あなたのページにposition: fixed;要素がなければ、次のようになります。

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

一方、 do にこの検索に巻き込まれる可能性のある位置固定要素がある場合は、残念ながら(そしてゆっくりと) 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は、Edgeのケースが多いため、もう少し簡単ですが、やはりかなり遅くなるので、この操作を何度も繰り返さなければならない場合は、回避するのが最善です。

470
AlexZ

他のすべての解決策は私のためにいくつかの状況のた​​めに壊れました..

勝利の答えが次の場所で壊れるのを見てください。

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

86
guy mograbi

ユーザーに表示されることに興味があるなら:

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;
}

テスト済み( モカ 用語を使用):

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;
    });
});
37
Ohad Navon

これは役に立つかもしれません: 一番左の位置に配置することで要素を隠してから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 hidden!!");        
}

jsFiddle

31
Ashad Shanto

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に感謝します。

24
Yvan

カップルの答えを組み合わせると、上記のようになります。

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の背後に隠されたりする可能性があります。あるいは、その内容は見えなくても境界線は見えている可能性があります。ある程度「目に見える」は主観的な用語です。

8
Matthew

Elementが標準的に表示されている(display:blockおよびvisibillity:visible)が、親コンテナが隠れている場合は、 clientWidth および clientHeight を使用して確認できます。

function isVisible (ele) {
  return  ele.clientWidth !== 0 &&
    ele.clientHeight !== 0 &&
    ele.style.opacity !== 0 &&
    ele.style.visibility !== 'hidden';
}

プランカー(ここをクリック)

7
Vlada

私は AlexZのgetComputedStyle()ソリューション と比較してより高性能な解決策を得ました。

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メソッド/プロパティを問題なく実行できるかぎり、表示要素を表示することを検討しています(たとえopacityが0でもCSS表示プロパティが 'hidden'でも).

6
Munawwar

基本的な可視性の検出方法を集めているだけなら、忘れないでください。

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

そしてどのように属性を取得するかに関しては:

element.getAttribute(attributename);

だから、あなたの例では:

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

しかし、何ですか?ここでは動作しません。よく見ると、可視性は要素の属性としてではなく、styleプロパティを使用して更新されていることがわかります。これはあなたがしていることをやろうとすることに関する多くの問題のうちの1つです。とりわけ、要素の可視性、表示、不透明度がすべて正しい値を持つという理由だけで、要素に実際に表示するものがあることを保証することはできません。それでもコンテンツが足りないか、高さと幅が足りない可能性があります。別のオブジェクトがそれをあいまいにする可能性があります。もっと詳しく知りたい場合は、Googleのクイック検索で this が表示され、問題を解決するためのライブラリも含まれます。 (YMMV)

強力なJohn Resigからの洞察を含め、優れた答えとともに、この質問の可能な重複である以下をチェックしてください。ただし、特定のユースケースは標準のユースケースとは多少異なるため、フラグを立てることは控えます。

(編集:OPは彼がスクラップページを作成していますが、それらを作成していません、SO以下は適用できません) Angularがng-showと同じように、要素の可視性をモデルプロパティにバインドし、常に可視性をそのモデルに依存するようにします。あなたはそれをあなたが望むどんなツールを使ってもすることができる:Angular、プレーンなJS、その他何でも。さらに良いことに、あなたはDOMの実装を時間の経過とともに変更することができますが、常にDOMではなくモデルから状態を読み取ることができるでしょう。 DOMからあなたの真実を読むことは悪いです。そして遅い。モデルをチェックし、DOMの状態がモデルを反映していることを確認するために実装を信頼してください。 (そしてその仮定を確認するために自動テストを使用します。)

5
XML

それで私が見つけたものは最も実行可能な方法です:

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

これは以下の事実に基づいています。

  • display: none要素は(入れ子になったものであっても)幅も高さも持っていません。
  • visiblityはネストした要素でもhiddenです。

そのため、どの親にvisibility: hiddenがあるかをテストするためにoffsetParentをテストしたり、DOMツリーをループアップしたりする必要はありません。これはIE 9でも動作するはずです。

opacity: 0と折りたたまれた要素(幅​​はあるが高さはない - あるいはその逆)も実際には見えないかどうかを議論することができます。しかし、その場合もやはり彼らは隠されているわけではありません。

3
Tokimon

オハドナボンの答えに少し追加。

要素の中心が他の要素に属している場合は見つかりません。

そのため、要素の点の1つが表示されていることを確認するために

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;
}
3
Guy Messika

参考までに、getBoundingClientRect()は特定のケースで機能することに注意してください。

たとえば、display: noneを使用して要素が隠されていることを簡単にチェックすると、次のようになります。

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

幅がゼロ、高さがゼロ、position: fixedの場合もカバーされるため、これも便利です。ただし、opacity: 0またはvisibility: hiddenで隠された要素は報告されません(ただし、offsetParentも報告されません)。

2
incarnate

からのjQueryコード - http://code.jquery.com/jquery-1.11.1.js には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 );
};

そのため、オーナー文書に関連する追加のチェックがあるように見えます

これが本当に次のようなケースを捕らえるのだろうか。

  1. ZIndexに基づいて他の要素の後ろに隠された要素
  2. 完全に透明な要素を非表示にする
  3. 画面外に配置された要素(左:-1000px)
  4. 可視性のある要素:非表示
  5. 表示要素:なし
  6. テキストやサブ要素が表示されていない要素
  7. 高さまたは幅が0に設定されている要素
2
Scott Izu

@Guy Messikaの 答えを上に改良 し、中心点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;
}
1
Israel

これは、要素とそのすべての先祖が可視の場合に限りtrueを返します。 displayおよびvisibilitystyleプロパティのみを調べます。

    var isVisible = function(el){
        // returns true iff el and all its ancestors are visible
        return el.style.display !== 'none' && el.style.visibility !== 'hidden'
        && (el.parentElement? isVisible(el.parentElement): true)
    };
1
Max Heiber

これは、可視性を含むすべての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特性のために働き、非常に用途が広く信頼性があります。

0
William Green

これは私がしたことです:

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>
0
Ajas Jansher

これが私が書いたコードで、いくつかの類似した要素の中で唯一目に見えるものを見つけ、jQueryを使わずにその "class"属性の値を返します。

  // 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");
    }
  }
0
not_specified