ChatGPT解决这个技术问题 Extra ChatGPT

Check if element is visible in DOM

Is there any way that I can check if an element is visible in pure JS (no jQuery) ?

So, given a DOM element, how can I check if it is visible or not? I tried:

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

but it doesn't seem to be working. I wonder which attributes should I check. It comes to my mind:

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

Any others that I might be missing?

That doesn't use display, it uses visibility so check for visibility (hidden or visible). ex: document.getElementById('snDealsPanel').style.visibility
PSL. If I would like to do this more general, which attributes should I check: visibility, display...?
You can make it generic in your own way but what i am saying is it uses visibility inspecting the element.
Here is my code (no jquery) for this question stackoverflow.com/a/22969337/2274995
Link is broken which makes your question not easy to understand. Kindly re-frame it.

7
7ochem

According to this MDN documentation, an element's offsetParent property will return null whenever it, or any of its parents, is hidden via the display style property. Just make sure that the element isn't fixed. A script to check this, if you have no position: fixed; elements on your page, might look like:

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

On the other hand, if you do have position fixed elements that might get caught in this search, you will sadly (and slowly) have to use window.getComputedStyle(). The function in that case might be:

// 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')
}

Option #2 is probably a little more straightforward since it accounts for more edge cases, but I bet its a good deal slower, too, so if you have to repeat this operation many times, best to probably avoid it.


Also FYI, just discovered that el.offsetParent wasn't working on IE9 for non-fixed elements. Or so it seems, anyway. (OK for IE11, though.) So went with getComputedStyle after all.
alas! getComputedStyle does not work correctly: plnkr.co/edit/6CSCA2fe4Gqt4jCBP2wu?p=preview However, so does offsetParent - perhaps a combination of the two should be used?
for ie9+ie10 you can check if offsetParent = body for non visible elements.
i am seeing getComputedStyle(element).display having the value of table in some elements (for instance TABLE elements) whose ancestor is display:none making is essentially useless.
Just a note on the window.getComputedStyle method, it returns a live CSSStyleDeclaration object. So you only have to grab the style once, then can re-check the object if you have to perform the check multiple times.
g
guy mograbi

All the other solutions broke for some situation for me..

See the winning answer breaking at:

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

Eventually, I decided that the best solution was $(elem).is(':visible') - however, this is not pure javascript. it is jquery..

so I peeked at their source and found what I wanted

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

This is the source: https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js


This will return true for an element with visibility:hidden
@YuvalA.: Yeah because the element is still visible. Setting a element to visibility:hidden shows no content anymore, but still takes the width and height of the element!
OP asked for a solution with no jQuery
For anyone looking for a version that also works with visibility:hidden, adding && window.getComputedStyle(elem).visibility !== "hidden" to the end of this return line seems to work
@DougWilhelm That's why the source code is shown. The source code is pure javascript, since jQuery doesn't use other libraries at this place.
O
Ohad Navon

If you're interested in visible by the user:

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

Tested on (using mocha terminology):

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

an edge case if the elem is positioned outside of the viewport, can be caught by "if (!pointContainer) return false;" checking the first pointContainer
If you want to check whether the user could possibly see it, you would have to use a scrollIntoView right?! This is quite expensive. Is there another clever way?
What about a case when overlapping element (to be precise: all overlapping elements) has opacity < 1?
Lifesaver. Js is such a ... language
Y
Yvan

Use the same code as jQuery does:

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

So, in a function:

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

Works like a charm in my Win/IE10, Linux/Firefox.45, Linux/Chrome.52...

Many thanks to jQuery without jQuery!


Nice but doesn't cover elements being hidden by overflow.
nice but what why !! (double negation)?
To force the result as boolean. As e.offsetWidth is an integer, !e.offsetWidth will return false if e.offsetWidth is higher than zero (element is visible). So adding another ! as in !!e.offsetWidth will return true if e.offsetWidth is higher than zero. It's a shorthand for return e.offsetWidth > 0 ? true : false or obviously return e.offsetWidth > 0.
So if I wanted a "isHidden" function instead, I would use a single ! instead of !!?
@Jarad you're right :-) The double !! is used to force result to boolean. But as you want the opposite, only one is needed.
H
Harry B

This may help : Hide the element by positioning it on far most left position and then check the offsetLeft property. If you want to use jQuery you can simply check the :visible selector and get the visibility state of the element.

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


The OP requests a no-jQuery answer.
It was edited later i guess. When I answered it wasn't mentioned in the thread.
@StephenQuan, I've updated the answer with both jQuery and javaScript solution.
for the jQuery example, shouldn't the alert say "Div is visible?"
I wouldn't want to conclude an element is entirely hidden just because its offsetLeft is less than 0: what if it's only a small number of pixels less than 0 and its right-hand part is visible? (I agree this would seem like a silly design, but you never know with web designers these days.) It's probably better to add the width to offsetLeft and see if the result is still less than 0. Just in case.
L
Lee Taylor

The accepted answer did not work for me.

Year 2020 breakdown.

The (elem.offsetParent !== null) method works fine in Firefox but not in Chrome. In Chrome position: fixed will also make offsetParent return null even the element if visible in the page. User Phrogz conducted a large test (2,304 divs) on elements with varying properties to demonstrate the issue. https://stackoverflow.com/a/11639664/4481831 . Run it with multiple browsers to see the differences. Demo: //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

The (getComputedStyle(elem).display !== 'none') does not work because the element can be invisible because one of the parents display property is set to none, getComputedStyle will not catch that. Demo: var child1 = document.querySelector('#child1'); console.log(getComputedStyle(child1).display); //child will show "block" instead of "none" The (elem.clientHeight !== 0). This method is not influenced by position: fixed and it also check if element parents are not-visible. But it has problems with simple elements that do not have a css layout, see more here Demo: console.log(document.querySelector('#div1').clientHeight); //not zero console.log(document.querySelector('#span1').clientHeight); //zero
test1 div
test2 span The (elem.getClientRects().length !== 0) may seem to solve the problems of the previous 3 methods. However it has problems with elements that use CSS tricks (other then display: none) to hide in the page. Demo 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);
not visible 1
not visible 3

Conclusion.

So what I have showed you is that no method is perfect. To make a proper visibility check, you must use a combination of the last 3 methods.


In Chrome 88.0.4324.104 the first result give me null, null.
U
Unmitigated

Combining a couple answers above:

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

Like AlexZ said, this may be slower than some of your other options if you know more specifically what you're looking for, but this should catch all of the main ways elements are hidden.

But, it also depends what counts as visible for you. Just for example, a div's height can be set to 0px but the contents still visible depending on the overflow properties. Or a div's contents could be made the same color as the background so it is not visible to users but still rendered on the page. Or a div could be moved off screen or hidden behind other divs, or it's contents could be non-visible but the border still visible. To a certain extent "visible" is a subjective term.


Nice, but style.opacity, style.height and style.width return a string so it won't work with !==
Another way that an element could be hidden via style is that it's color could match the background color, or it's z-index could be lower than other elements.
adding display:none to this would be great. A proper working solution!
M
Mac Ignacio

2021 solution

According to MDN docs an interaction observer asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. This means every time the element intersects with the viewport the interaction observer will trigger.

As of 2021, all the current browser supports intersection observer except IE.

Implementation

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); // Asynchronous call

Important note: IntersectionObserver callback is asynchronous => you won't get result immediately after you call observer.observe(el);
Does this only trigger when a change in visibility is made?
IE, will it fire when initially created?
C
Community

I've got a more performant solution compared to AlexZ's getComputedStyle() solution when one has position 'fixed' elements, if one is willing to ignore some edge cases (check comments):

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

Side note: Strictly speaking, "visibility" needs to be defined first. In my case, I am considering an element visible as long as I can run all DOM methods/properties on it without problems (even if opacity is 0 or CSS visibility property is 'hidden' etc).


V
Vlada

If element is regular visible (display:block and visibillity:visible), but some parent container is hidden, then we can use clientWidth and clientHeight for check that.

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' is redundant here. In that case, clientWidth and clientHeight will be 0.
Opacity check needs to be coerced to number, because style values are all strings. Eg, parseFloat(ele.style.opacity) < 0.1
T
Tokimon

So what I found is the most feasible method:

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

This is build on these facts:

A display: none element (even a nested one) doesn't have a width nor height.

visiblity is hidden even for nested elements.

So no need for testing offsetParent or looping up in the DOM tree to test which parent has visibility: hidden. This should work even in IE 9.

You could argue if opacity: 0 and collapsed elements (has a width but no height - or visa versa) is not really visible either. But then again they are not per say hidden.


G
Guy Messika

A little addition to ohad navon's answer.

If the center of the element belongs to the another element we won't find it.

So to make sure that one of the points of the element is found to be visible

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

C
Community

If we're just collecting basic ways of detecting visibility, let me not forget:

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

And as to how to obtain attributes:

element.getAttribute(attributename);

So, in your example:

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

But wha? It doesn't work here. Look closer and you'll find that visibility is being updated not as an attribute on the element, but using the style property. This is one of many problems with trying to do what you're doing. Among others: you can't guarantee that there's actually something to see in an element, just because its visibility, display, and opacity all have the correct values. It still might lack content, or it might lack a height and width. Another object might obscure it. For more detail, a quick Google search reveals this, and even includes a library to try solving the problem. (YMMV)

Check out the following, which are possible duplicates of this question, with excellent answers, including some insight from the mighty John Resig. However, your specific use-case is slightly different from the standard one, so I'll refrain from flagging:

How to tell if a DOM element is visible in the current viewport?

How to check if an element is really visible with javascript?

(EDIT: OP SAYS HE'S SCRAPING PAGES, NOT CREATING THEM, SO BELOW ISN'T APPLICABLE) A better option? Bind the visibility of elements to model properties and always make visibility contingent on that model, much as Angular does with ng-show. You can do that using any tool you want: Angular, plain JS, whatever. Better still, you can change the DOM implementation over time, but you'll always be able to read state from the model, instead of the DOM. Reading your truth from the DOM is Bad. And slow. Much better to check the model, and trust in your implementation to ensure that the DOM state reflects the model. (And use automated testing to confirm that assumption.)


I am parsing sites, this is not for my own site... :)
B
BorisOkunskiy

Just for the reference it should be noted that getBoundingClientRect() can work in certain cases.

For example, a simple check that the element is hidden using display: none could look somewhat like this:

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

This is also handy because it also covers zero-width, zero-height and position: fixed cases. However, it shall not report elements hidden with opacity: 0 or visibility: hidden (but neither would offsetParent).


Best answer for me... simple and effective. And no single upvote after 3 years! Goes on to show the worth of “crowd wisdom”. My version: var isVisible = el => (r => r.width && r.height)(el.getBoundingClientRect());. Then I can filter arrays of elements in the following way: $$(sel).filter(isVisible).
This does not work when visible to the user.... if you scroll away it will remain true
@RayFoss you do understand that there are various definitions to "visible", right? :) Just to make it clear "Visible in DOM" or "Visible on screen" or "Visible in viewport" or "Visible within the container with scrollbars" — all of those mean different things and implementations. Also, how visible is the element? Is it only visible when all of its pixels are rendered? (what about transforms?) Or, otherwise, is it visible if only its "conceptually transparent" padding is currently on screen? To summarize, I think the definition will depend a lot about your specific use case.
I
Israel

Improving on @Guy Messika's answer above, breaking and returning false if the center point' X is < 0 is wrong as the element right side may go into the view. here's a fix:

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

S
Scott Izu

The jQuery code from http://code.jquery.com/jquery-1.11.1.js has an isHidden param

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

So it looks like there is an extra check related to the owner document

I wonder if this really catches the following cases:

Elements hidden behind other elements based on zIndex Elements with transparency full making them invisible Elements positioned off screen (ie left: -1000px) Elements with visibility:hidden Elements with display:none Elements with no visible text or sub elements Elements with height or width set to 0


L
LeeNeverGup

To elaborate on everyone's great answers, here is the implementation that was used in the Mozilla Fathom project:

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

It checks on every parent's opacity, display, and rectangle.


k
ketzer
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');
}

Please don't post code-only answers. For future readers it's far more interesting to see explained why this answers the question. Also, you need to explain even more when you answer an old, already well answered question.
A
A.Mizrahi

const isVisible = (selector) => { let selectedElement let topElement let selectedData selectedElement = document.querySelector(selector) if (!selectedElement) { return false } selectedData = selectedElement.getBoundingClientRect() if (!selectedData || !Object.keys(selectedData)) { return false } if (!(selectedData.width > 0) || !(selectedData.height > 0)) { return false } topElement = document.elementFromPoint(selectedData.top, selectedData.left) if (selectedElement !== topElement) { return false } return true } const output = document.querySelector('.text') output.innerHTML = '.x element is visible: ' + isVisible('.x') .block { width: 100px; height: 100px; background: black; } .y { background: red; margin-top: -100px; }


This may not work if the element is partially obscured (on its top-left corner) by another overlapping element
M
Mahozad

Chrome 103 introduced Element.isVisible() which returns true if the element is visible, and false if it is not.

It checks a variety of factors that would make an element invisible, including display:none, visibility, content-visibility, and opacity.


It is available in stable, but it is currently only available behind a feature flag (7/13/2022).
n
not_specified

Here's the code I wrote to find the only visible among a few similar elements, and return the value of its "class" attribute without 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");
    }
  }

S
Stuart Rucker

If you are scraping sites, one very inefficient method which worked for me was highlighting whatever element, and screenshotting, and then checking if the screenshot has changed.

//Screenshot

function makeSelected(element){
    let range = new Range()
    range.selectNode(element)
    let selection = window.getSelection()
    selection.removeAllRanges()
    selection.addRange(range)
}
// screenshot again and check for diff

W
William Green

This is a way to determine it for all css properties including visibility:

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

It works for any css property and is very versatile and reliable.


[element.style.display == "none"] is working for me
A
Ajas Jansher

This is what I did:

HTML & CSS: Made the element hidden by default

<html>
<body>

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

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

</body>
</html> 

JavaScript: Added a code to check whether the visibility is hidden or not:

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

H
Hüseyin Çakanlı
var visible = document.getElementById("yourelementID's");
 if (visible){
          // make events
 } else
 {
   //other events
 }

This does not check if an element is visible. It checks if it is in the DOM. It could be in the DOM and hidden, not displayed, covered up by another element, or positioned outside the viewport.
D
DMur

There are many situations where this will not necessarily work, however in my case I'm using this and it works fine for what I need. So if you are looking for a basic solution (Which does not cover every eventuality) it 'might' be helpful to you, if this simple solution suits your particular need.

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

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

<!-- element is visible -->

} else {

<!-- element is hidden-->

}

There are so many situations where this obviously won't work, since display: block is not the only style an element can have and still be visible.