Проверьте, видим ли элемент в DOM
Можно ли как-то проверить, виден ли элемент в чистом JS (нет jQuery)?
Так, например, на этой странице: Performance Bikes, если вы наводите курсор мыши на Deals (в верхнем меню), появляется окно сделок, но в начале оно не отображалось. Это в HTML, но это не видно.
Итак, учитывая элемент DOM, как я могу проверить, виден ли он или нет? Я старался:
window.getComputedStyle(my_element)['display']);
но это не похоже на работу. Интересно, какие атрибуты я должен проверить. Это приходит мне в голову:
display !== 'none'
visibility !== 'hidden'
Любые другие, которые я мог бы пропустить?
32 ответа
Согласно этой документации 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, вероятно, немного проще, так как он учитывает больше крайних случаев, но я держу пари, что он тоже намного медленнее, поэтому, если вам придется повторять эту операцию много раз, лучше всего избегать ее.
Все остальные решения сломались для какой-то ситуации для меня..
Смотрите победный ответ, разбив на:
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
Если вас интересует видимое пользователем:
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;
});
});
Используйте тот же код, что и 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!
Представлены Chrome 105 (а также Edge и Opera) и Firefox 106.Element.checkVisibility()
который возвращаетtrue
если элемент виден, иfalse
в противном случае.
Функция проверяет множество факторов, которые сделали бы элемент невидимым, в том числеdisplay:none
,visibility
,content-visibility
, иopacity
:
let element = document.getElementById("myIcon");
let isVisible = element.checkVisibility({
checkOpacity: true, // Check CSS opacity property too
checkVisibilityCSS: true // Check CSS visibility property too
});
Примечание : ранее называлсяisVisible()
. См. этот выпуск GitHub .
ВидетьcheckVisibility()
спецификация проект здесь .
Принятый ответ у меня не сработал. Ответ 2020 года:
1) Метод (elem.offsetParent!== null) отлично работает в Firefox, но не в Chrome. Для Chrome "положение: исправлено;" также заставит offsetParent возвращать "null", даже если элемент отображается на странице.
Демо:
//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>
вы можете увидеть этого парня на мегатесте /questions/35745237/chto-byi-sdelat-offsetparent-nulevyim/35745243#35745243 (запустите его с несколькими браузерами, чтобы увидеть различия).
2) (getComputedStyle(elem).display!== 'none') не работают, потому что элемент может быть невидимым, поскольку для одного из родительских свойств display установлено значение 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>
3) (elem.clientHeight!== 0). На этот метод не влияет фиксированная позиция, и он также проверяет, не видны ли родители элементов. Но у него проблемы с простыми элементами, у которых нет макета css, подробнее здесь
Демо:
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>
4) (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 методов.
Это может помочь: скрыть элемент, расположив его в крайнем крайнем левом положении, а затем проверить свойство 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!!");
}
Решение 2021 года
Согласно документации MSD, наблюдатель взаимодействия асинхронно наблюдает изменения в пересечении целевого элемента с элементом-предком или с окном просмотра документа верхнего уровня. Это означает, что каждый раз, когда элемент пересекается с окном просмотра, срабатывает наблюдатель взаимодействия.
С 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);
Объединяя пару ответов выше:
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, или его содержимое может быть невидимым, но граница все еще видна. В определенной степени "видимый" является субъективным термином.
У меня есть более эффективное решение по сравнению с решением 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 скрыто и т. Д.).
Если элемент виден регулярно (display:block и visibillity:visible), но некоторый родительский контейнер скрыт, то мы можем использовать clientWidth и clientHeight для проверки этого.
function isVisible (ele) {
return ele.clientWidth !== 0 &&
ele.clientHeight !== 0 &&
ele.style.opacity !== 0 &&
ele.style.visibility !== 'hidden';
}
Небольшое дополнение к ответу Охада Навона.
Если центр элемента принадлежит другому элементу, мы его не найдем.
Таким образом, чтобы убедиться, что одна из точек элемента найдена видимой
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;
}
Просто для справки следует отметить, что getBoundingClientRect()
может работать в определенных случаях.
Например, простая проверка, что элемент скрыт с помощью display: none
может выглядеть примерно так:
var box = element.getBoundingClientRect();
var visible = box.width && box.height;
Это также удобно, потому что оно также охватывает нулевую ширину, нулевую высоту и position: fixed
случаев. Тем не менее, он не должен сообщать об элементах, скрытых с opacity: 0
или же visibility: hidden
(но не будет offsetParent
).
Так что я нашел самый выполнимый метод:
function visible(elm) {
if(!elm.offsetHeight && !elm.offsetWidth) { return false; }
if(getComputedStyle(elm).visibility === 'hidden') { return false; }
return true;
}
Это основано на следующих фактах:
display: none
элемент (даже вложенный) не имеет ни ширины, ни высоты.visiblity
являетсяhidden
даже для вложенных элементов.
Так что нет необходимости в тестировании offsetParent
или цикл в дереве DOM, чтобы проверить, какой родитель имеет visibility: hidden
, Это должно работать даже в IE 9.
Вы могли бы поспорить, если opacity: 0
и свернутые элементы (имеет ширину, но не высоту - или наоборот) также не видны. Но опять же, они, по-видимому, не скрыты.
Если мы просто собираем основные способы определения видимости, позвольте мне не забыть:
opacity > 0.01; // probably more like .1 to actually be visible, but YMMV
А что касается того, как получить атрибуты:
element.getAttribute(attributename);
Итак, в вашем примере:
document.getElementById('snDealsPanel').getAttribute('visibility');
А чего? Это не работает здесь. Посмотрите внимательнее, и вы увидите, что видимость обновляется не как атрибут элемента, а с использованием style
имущество. Это одна из многих проблем, связанных с попытками сделать то, что вы делаете. Среди прочего: вы не можете гарантировать, что на самом деле есть что-то, что можно увидеть в элементе, просто потому что его видимость, отображение и прозрачность имеют правильные значения. В нем по-прежнему может отсутствовать содержимое или высота и ширина. Другой объект может скрыть это. Для более подробной информации, быстрый поиск Google показывает это, и даже включает в себя библиотеку, чтобы попытаться решить проблему. (YMMV)
Проверьте следующее, которые являются возможными дубликатами этого вопроса, с отличными ответами, в том числе с пониманием могучего Джона Резига. Однако ваш конкретный вариант использования немного отличается от стандартного, поэтому я воздержусь от пометки:
- Как определить, виден ли элемент DOM в текущем окне просмотра?
- Как проверить, действительно ли элемент виден в javascript?
(РЕДАКТИРОВАТЬ: ОП СКАЗЫВАЕТ, ЧТО ОН УЖАСИТ СТРАНИЦЫ, НЕ СОЗДАВАЯ ИХ, ТАК НИЖЕ НЕ ПРИМЕНИМО) Привязать видимость элементов к свойствам модели и всегда делать видимость зависимой от этой модели, как это делает Angular с ng-show. Вы можете сделать это, используя любой инструмент, который вам нужен: угловой, простой JS, что угодно. Более того, вы можете со временем изменить реализацию DOM, но вы всегда сможете читать состояние из модели, а не из DOM. Чтение вашей правды из DOM - это плохо. И медленно. Намного лучше проверить модель и довериться реализации, чтобы убедиться, что состояние DOM отражает модель. (И используйте автоматическое тестирование, чтобы подтвердить это предположение.)
Чтобы подробно рассказать об отличных ответах каждого, вот реализация, которая использовалась в проекте Mozilla Fathom:
/**
* 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;
}
Он проверяет прозрачность, отображение и прямоугольник каждого родителя.
Улучшение ответа @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;
}
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');
}
Код 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 );
};
Похоже, что есть дополнительная проверка, связанная с документом владельца
Интересно, действительно ли это ловит следующие случаи:
- Элементы скрыты за другими элементами на основе zIndex
- Элементы с полной прозрачностью делают их невидимыми
- Элементы расположены вне экрана (т.е. слева: -1000 пикселей)
- Элементы с видимостью: скрытые
- Элементы с дисплеем: нет
- Элементы без видимого текста или вложенных элементов
- Элементы с высотой или шириной, установленной на 0
Это возвращает истину, если и только если элемент и все его предки видимы. Это только смотрит на 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)
};
Вот функция (чистый ванильный JS), которая выполняет большое количество проверок, гарантируя, что данный элемент виден пользователю:
function isVisible(element) {
// Check if the element is null or undefined
if (!element) return false;
// Get the element's bounding client rect
const boundingRect = element.getBoundingClientRect();
// Check if the element has a positive width and height
if (boundingRect.width <= 0 || boundingRect.height <= 0) return false;
// Check if the element's top and left values are within the viewport
const top = boundingRect.top;
const left = boundingRect.left;
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
if (top > viewportHeight || left > viewportWidth) return false;
// Check if the element's right and bottom values are within the viewport
const right = boundingRect.right;
const bottom = boundingRect.bottom;
if (right < 0 || bottom < 0) return false;
// Check if the element is hidden by the overflow property
const parentNode = element.parentNode;
if (parentNode && getComputedStyle(parentNode).overflow === 'hidden') {
const parentRect = parentNode.getBoundingClientRect();
if (top < parentRect.top || bottom > parentRect.bottom || left < parentRect.left || right > parentRect.right) {
return false;
}
}
const elementComputedStyle = getComputedStyle(element);
// Check if the element has a z-index of less than 0
const zIndex = elementComputedStyle.zIndex;
if (zIndex < 0) return false;
// Check if the element has a display value of 'none' or an opacity of 0
const display = elementComputedStyle.display;
const opacity = elementComputedStyle.opacity;
if (display === 'none' || opacity === '0') return false;
// Check if the element is hidden by an ancestor element with a display value of 'none' or an opacity of 0
let ancestorElement = element.parentElement;
while (ancestorElement) {
const ancestorComputedStyle = getComputedStyle(ancestorElement);
const ancestorDisplay = ancestorComputedStyle.display;
const ancestorOpacity = ancestorComputedStyle.opacity;
if (ancestorDisplay === 'none' || ancestorOpacity === '0') return false;
ancestorElement = ancestorElement.parentElement;
}
// Initialize a variable to keep track of whether the element is obscured by another element
let obscured = false;
// Check if the element is obscured by another element according to its position
if (elementComputedStyle.position === 'absolute' || elementComputedStyle.position === 'fixed' ||
elementComputedStyle.position === 'relative' || elementComputedStyle.position === 'sticky' ||
elementComputedStyle.position === 'static') {
let siblingElement = element.nextElementSibling;
while (siblingElement) {
if (siblingElement.getBoundingClientRect().top > boundingRect.bottom || siblingElement.getBoundingClientRect().left > boundingRect.right) {
break;
}
if (siblingElement.getBoundingClientRect().bottom > boundingRect.top && siblingElement.getBoundingClientRect().right > boundingRect.left) {
obscured = true;
break;
}
siblingElement = siblingElement.nextElementSibling;
}
if (obscured) return false;
}
// If all checks have passed, the element is visible
return true;
}
Это решение работает с элементами нулевой высоты:
const divElement = document.getElementById('yourDivId'); // Replace 'yourDivId' with the actual ID of your div
const rect = divElement.getBoundingClientRect();
const isVisible = rect.bottom > 0 && rect.top < window.innerHeight;
if (isVisible) {
console.log('The div is visible.'); // Or partially visible
} else {
console.log('The div is not visible.');
}
Использование jquery$("ваш-селектор: видимый"). Length; // возвращаем 1, если видим, else 0 например $ (". custom-control-input: visible"). length; // если этот элемент виден на экране, он вернет 1
Если вы парсите сайты, один очень неэффективный метод, который сработал для меня, заключался в выделении любого элемента и снимке экрана, а затем проверке того, изменился ли снимок экрана.
//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
2023 Решение :)
с плагином jquery
$.fn.isvisible = function(e) {
var style = window.getComputedStyle($(this)[0]);
return (style.display != 'none')
}
alert($('.classname').isvisible())
Вот что я сделал:
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>
Я использую это. У меня работает нормально.
var element= document.getElementById('elementId');
if (element.style.display == "block"){
<!-- element is visible -->
} else {
<!-- element is hidden-->
}
Если вы столкнулись с текстовыми узлами, попробуйте следующее:
// Where n a node you'd like to test for visibility
function isHidden(n) {
if(n.nodeType==3){
el = n.parentElement;
}else{
el = n;
}
return (el.offsetParent === null)
}
Вот код, который я написал, чтобы найти единственное видимое среди нескольких похожих элементов и вернуть значение его атрибута "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");
}
}