Проверьте, виден ли элемент в DOM

Есть ли какой-нибудь способ, которым я могу проверить, виден ли элемент в чистом JS (без jQuery) ?

Так, например, на этой странице: Performance Bikes, если вы наводите курсор на Deals (в верхнем меню), появляется окно сделок, но в начале оно не показывалось. Это в HTML, но это не видно.

Итак, учитывая элемент DOM, как я могу проверить, является ли он видимым или нет? Я пытался:

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

но это не работает. Интересно, какие атрибуты я должен проверить. Это приходит мне в голову:

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

Любые другие, которые я мог бы пропустить?

Комментарии к вопросу (4)
Решение

Согласно этой документации 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)
}

С другой стороны, если у вас есть фиксированные элементы положения, которые могут быть пойманы в этом поиске, вам, к сожалению (и медленно) придется использовать 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, вероятно, немного более прост, поскольку он учитывает больше крайних случаев, но держу пари, что он также намного медленнее, поэтому, если вам придется повторять эту операцию много раз, лучше всего, вероятно, избегать ее.

Комментарии (19)

Все остальные решения сломались для какой-то ситуации для меня..

Смотрите выигрышный ответ, ломая на:

http://plnkr.co/edit/6CSCA2fe4Gqt4jCBP2wu?р = предварительный просмотр

В конце концов я решил, что лучшим решением было $ (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

Комментарии (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;
    });
});
Комментарии (2)

Это может помочь: Спрячьте элемент, поместив его в крайнее левое положение, а затем проверьте свойство offsetLeft. Если вы хотите использовать jQuery, вы можете просто проверить < a href = "http://api.jquery.com/visible-selector/" > : visible < / a > селектор и получить состояние видимости элемента.

HTML:

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

CSS:


#myDiv{
   position:absolute;
   left : -2000px;
}


#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!!");        
}
< a href = "http://jsfiddle.net/codeSpy/Nr99p/" > ***jsFiddle***
Комментарии (7)

Используйте тот же код, что и 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!

Комментарии (3)

Объединяя пару ответов выше:

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, или его содержимое может быть невидимым, но граница все еще видна. В определенной степени «видимый» - это субъективный термин.

Комментарии (3)

Если элемент хорошо виден (отображение: блок и видимость: видимый), но какой-то родительский контейнер скрыт, то мы можем использовать clientWidth и clientHeight для проверки этого.

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

Plunker (нажмите здесь)

Комментарии (1)

У меня есть более производительное решение по сравнению с решением 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 (даже если непрозрачность равна 0 или свойство видимости CSS «скрыто» и т. Д.).

Комментарии (0)

Если мы просто собираем основные способы обнаружения видимости, позвольте мне не забывать:

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)

Проверьте следующее, которые являются возможными дубликатами этого вопроса, с отличными ответами, включая некоторое понимание от могущественного Джона Ресига. Тем не менее, ваш конкретный вариант использования немного отличается от стандартного, поэтому я воздержусь от пометки:

(ЭДИТ: ОП говорит, что он ломает страницы, а не создает их, так что ниже не применимо) Лучший вариант? Свяжите видимость элементов с свойствами модели и всегда делайте видимость зависимой от этой модели, так же, как Angular делает с ng-show. Вы можете сделать это, используя любой инструмент: угловой, простой JS, что угодно. Более того, вы можете со временем изменить реализацию DOM, но вы всегда сможете прочитать состояние из модели, а не DOM. Чтение вашей правды из DOM - это плохо. И медленно. Намного лучше проверить модель и доверять вашей реализации, чтобы гарантировать, что состояние DOM отражает модель. (И используйте автоматическое тестирование, чтобы подтвердить это предположение.)

Комментарии (1)

Для справки следует отметить, что getBoundingClientRect () может работать в определенных случаях.

Например, простая проверка того, что элемент скрыт с помощью display: none, может выглядеть примерно так:

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

Это также удобно, поскольку оно также охватывает случаи с нулевой шириной, нулевой высотой и «позицией: фиксированные». Однако он не должен сообщать элементы, скрытые с «непрозрачностью: 0» или «видимостью: скрытой» (но также не «offsetParent»).

Комментарии (3)

Итак, что я нашел, это наиболее выполнимый метод:

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

Это основано на этих фактах:

  • Элемент `display: ни один (даже вложенный) не имеет ни ширины, ни высоты.
  • «видимость» «скрыта» даже для вложенных элементов.

Таким образом, нет необходимости тестировать offsetParent или зацикливаться в дереве DOM, чтобы проверить, какой родитель имеет видимость: скрытая. Это должно работать даже в IE 9.

Вы можете поспорить, если «непрозрачность: 0» и свернутые элементы (имеют ширину, но не высоту - или наоборот) также не видны. Но опять же они не скрыты.

Комментарии (0)

Небольшое дополнение к ответу Охада Навона.

Если центр элемента принадлежит другому элементу, мы его не найдем.

Поэтому убедитесь, что одна из точек элемента найдена видимой

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;
}
Комментарии (0)

Улучшение @Guy Messika ответ выше, нарушение и возврат false, если центральная точка 'X < 0 неверно, так как правая сторона элемента может войти в представление. вот исправление:

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;
}
Комментарии (0)

Код 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
Комментарии (0)

Это возвращает true тогда и только тогда, когда элемент и все его предки видны. Он только рассматривает свойства стиля display и visibility:

    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)

Вот код, который я написал, чтобы найти единственный видимый из нескольких похожих элементов и вернуть значение его атрибута «class» без 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");
    }
  }
Комментарии (0)

Это то, что я сделал:

HTML & CSS: скрыт элемент по умолчанию




Click Me

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


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)

Это способ определить его для всех свойств 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)