Как определить, отображается ли элемент DOM в текущем окне просмотра?

Есть ли эффективный способ узнать, является ли элемент DOM (в документе HTML) в настоящее время видимым (отображается в окне просмотра)?

(Вопрос касается Firefox)

+787
23 сент. '08 в 21:24
источник поделиться
25 ответов

Обновление: Время идет, и у нас есть наши браузеры. Этот метод больше не рекомендуется, и вы должны использовать решение @Dan ниже (qaru.site/questions/10631/...), если вам не нужно поддерживать IE < 7.

Исходное решение (теперь устарело):

Это проверит, будет ли элемент полностью отображаться в текущем окне просмотра:

function elementInViewport(el) {
  var top = el.offsetTop;
  var left = el.offsetLeft;
  var width = el.offsetWidth;
  var height = el.offsetHeight;

  while(el.offsetParent) {
    el = el.offsetParent;
    top += el.offsetTop;
    left += el.offsetLeft;
  }

  return (
    top >= window.pageYOffset &&
    left >= window.pageXOffset &&
    (top + height) <= (window.pageYOffset + window.innerHeight) &&
    (left + width) <= (window.pageXOffset + window.innerWidth)
  );
}

Вы можете изменить это просто, чтобы определить, видима ли какая-либо часть элемента в окне просмотра:

function elementInViewport2(el) {
  var top = el.offsetTop;
  var left = el.offsetLeft;
  var width = el.offsetWidth;
  var height = el.offsetHeight;

  while(el.offsetParent) {
    el = el.offsetParent;
    top += el.offsetTop;
    left += el.offsetLeft;
  }

  return (
    top < (window.pageYOffset + window.innerHeight) &&
    left < (window.pageXOffset + window.innerWidth) &&
    (top + height) > window.pageYOffset &&
    (left + width) > window.pageXOffset
  );
}
+301
24 сент. '08 в 2:40
источник

Связанные вопросы


Похожие вопросы

Теперь большинство браузеров поддерживает getBoundingClientRect метод, которая стала лучшей практикой. Использование старого ответа очень медленно, неточно и имеет несколько ошибок.

Решение, выбранное как правильно, почти никогда не уточняется. Вы можете прочитать больше о своих ошибках.


Это решение было протестировано на IE7 +, iOS5 + Safari, Android2 +, Blackberry, Opera Mobile и IE Mobile 10.


function isElementInViewport (el) {

    //special bonus for those using jQuery
    if (typeof jQuery === "function" && el instanceof jQuery) {
        el = el[0];
    }

    var rect = el.getBoundingClientRect();

    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
    );
}

Как использовать:

Вы можете быть уверены, что приведенная выше функция возвращает правильный ответ в момент времени, когда он вызывается, но как насчет видимости элемента отслеживания в качестве события?

Поместите следующий код в нижней части тэга <body>:

function onVisibilityChange(el, callback) {
    var old_visible;
    return function () {
        var visible = isElementInViewport(el);
        if (visible != old_visible) {
            old_visible = visible;
            if (typeof callback == 'function') {
                callback();
            }
        }
    }
}

var handler = onVisibilityChange(el, function() {
    /* your code go here */
});


//jQuery
$(window).on('DOMContentLoaded load resize scroll', handler); 

/* //non-jQuery
if (window.addEventListener) {
    addEventListener('DOMContentLoaded', handler, false); 
    addEventListener('load', handler, false); 
    addEventListener('scroll', handler, false); 
    addEventListener('resize', handler, false); 
} else if (window.attachEvent)  {
    attachEvent('onDOMContentLoaded', handler); // IE9+ :(
    attachEvent('onload', handler);
    attachEvent('onscroll', handler);
    attachEvent('onresize', handler);
}
*/

Если вы внесете какие-либо изменения DOM, они могут, естественно, изменить видимость элемента.

Рекомендации и общие ошибки:

Возможно, вам нужно отслеживать масштабирование страницы/привязку мобильного устройства? jQuery должен обрабатывать масштабировать/зажимать кросс-браузер, иначе первая или вторая ссылка должна вам помочь.

Если вы измените DOM, это может повлиять на видимость элемента. Вы должны взять его под контроль и вызвать handler() вручную. К сожалению, у нас нет кросс-браузера onrepaint. С другой стороны, это позволяет нам оптимизировать и выполнять повторную проверку только на модификациях DOM, которые могут изменять видимость элементов.

Никогда никогда не используйте его внутри jQuery $(document).ready(), потому что в данный момент не существует гарантии CSS. Ваш код может работать локально с вашим CSS на жестком диске, но после его установки на удаленном сервере он не работает.

После запуска DOMContentLoaded применяются стили , но изображения еще не загружены. Итак, мы должны добавить window.onload прослушиватель событий.

Мы еще не можем уловить событие масштабирования/пинча.

Последним средством может быть следующий код:

/* TODO: this looks like a very bad code */
setInterval(handler, 600); 

Вы можете использовать потрясающую функцию pageVisibiliy API HTML5, если вам интересно, активна и видима вкладка с вашей веб-страницей.

TODO: этот метод не обрабатывает две ситуации:

+1219
26 сент. '11 в 15:27
источник

Update

В современных браузерах вы можете проверить API-интерфейс пересечения, который обеспечивает следующие преимущества:

  • Лучшая производительность, чем прослушивание событий прокрутки.
  • Работает в междоменных iframe
  • Может определить, что элемент препятствует/пересекает другой

Intersection Observer находится на пути к полноценному стандарту и уже поддерживается в Chrome 51+, Edge 15+ и Firefox 55+ и находится в разработке для Safari. Там также доступен polyfill.


Предыдущий ответ

Есть некоторые проблемы с ответом предоставленным Dan, который может сделать его непригодным для некоторых ситуаций. Некоторые из этих проблем указаны в его ответе в нижней части, что его код даст ложные срабатывания для элементов, которые:

  • Скрывается другим элементом перед тестируемым
  • Вне видимой области элемента parent или ancestor
  • Элемент или его дочерние элементы скрыты с помощью свойства CSS clip

Эти ограничения демонстрируются в следующих результатах простой тест:

Failed test, using isElementInViewport

Решение: isElementVisible()

Вот решение этих проблем, с приведенным ниже результатом теста и объяснением некоторых частей кода.

function isElementVisible(el) {
    var rect     = el.getBoundingClientRect(),
        vWidth   = window.innerWidth || doc.documentElement.clientWidth,
        vHeight  = window.innerHeight || doc.documentElement.clientHeight,
        efp      = function (x, y) { return document.elementFromPoint(x, y) };     

    // Return false if it not in the viewport
    if (rect.right < 0 || rect.bottom < 0 
            || rect.left > vWidth || rect.top > vHeight)
        return false;

    // Return true if any of its four corners are visible
    return (
          el.contains(efp(rect.left,  rect.top))
      ||  el.contains(efp(rect.right, rect.top))
      ||  el.contains(efp(rect.right, rect.bottom))
      ||  el.contains(efp(rect.left,  rect.bottom))
    );
}

Тест прохождения: http://jsfiddle.net/AndyE/cAY8c/

И результат:

Passed test, using isElementVisible

Дополнительные примечания

Однако этот метод не лишен собственных ограничений. Например, проверяемый элемент с более низким z-индексом, чем другой элемент в том же месте, будет идентифицирован как скрытый, даже если элемент впереди фактически не скрывает какой-либо его части. Тем не менее, этот метод использует его в некоторых случаях, когда решение Dan не распространяется.

Оба element.getBoundingClientRect() и document.elementFromPoint() являются частью спецификации рабочего проекта CSSOM и поддерживаются, по крайней мере, в IE 6 и более поздних версиях и в большинстве настольных браузеров в течение длительного времени (хотя и не идеально). Подробнее см. Quirksmode для этих функций.

contains() используется, чтобы узнать, является ли элемент, возвращаемый document.elementFromPoint() дочерним элементом node элемента, который мы тестируем для видимости. Он также возвращает true, если возвращаемый элемент является одним и тем же элементом. Это просто делает проверку более надежной. Он поддерживается во всех основных браузерах, Firefox 9.0 является последним из них, чтобы добавить его. Для более старой поддержки Firefox проверьте эту историю ответов.

Если вы хотите проверить больше элементов вокруг элемента для видимости, т.е. чтобы убедиться, что элемент не покрыт более чем, скажем, 50%, это не займет много времени, чтобы отрегулировать последнюю часть ответа, Однако имейте в виду, что это, вероятно, будет очень медленным, если вы проверили каждый пиксель, чтобы убедиться, что он был на 100% видимым.

+138
04 мар. '13 в 14:18
источник

Я попробовал Дэн ответить, однако алгебра, используемая для определения границ, означает, что элемент должен быть как ≤ размером окна просмотра, так и полностью внутри области просмотра, чтобы получить true, что легко приводит к ложным отрицаниям. Если вы хотите определить, находится ли элемент в области просмотра вообще, ответ ryanve близок, но проверяемый элемент должен перекрывать область просмотра, поэтому попробуйте следующее:

function isElementInViewport(el) {
    var rect = el.getBoundingClientRect();

    return rect.bottom > 0 &&
        rect.right > 0 &&
        rect.left < (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */ &&
        rect.top < (window.innerHeight || document.documentElement.clientHeight) /* or $(window).height() */;
}
+48
29 апр. '13 в 2:36
источник

Как общественная служба:
Дэн отвечает правильными вычислениями (элемент может быть > окном, особенно на экранах мобильного телефона), и исправить тестирование jQuery, а также добавить isElementPartiallyInViewport:

Кстати, разница между window.innerWidth и document.documentElement.clientWidth заключается в том, что clientWidth/clientHeight не включает полосу прокрутки, а window.innerWidth/Высота делает.

function isElementPartiallyInViewport(el)
{
    //special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];

    var rect = el.getBoundingClientRect();
    // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
    var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
    var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

    return (vertInView && horInView);
}


// http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
function isElementInViewport (el) 
{
    //special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];

    var rect = el.getBoundingClientRect();
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    return (
           (rect.left >= 0)
        && (rect.top >= 0)
        && ((rect.left + rect.width) <= windowWidth)
        && ((rect.top + rect.height) <= windowHeight)
    );

}


function fnIsVis(ele)
{
    var inVpFull = isElementInViewport(ele);
    var inVpPartial = isElementPartiallyInViewport(ele);
    console.clear();
    console.log("Fully in viewport: " + inVpFull);
    console.log("Partially in viewport: " + inVpPartial);
}

Тест-случай

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Test</title>
    <!--
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>    
    <script src="scrollMonitor.js"></script>
    -->

    <script type="text/javascript">

        function isElementPartiallyInViewport(el)
        {
            //special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];

            var rect = el.getBoundingClientRect();
            // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
            var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
            var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

            return (vertInView && horInView);
        }


        // http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
        function isElementInViewport (el) 
        {
            //special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];


            var rect = el.getBoundingClientRect();
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            return (
                   (rect.left >= 0)
                && (rect.top >= 0)
                && ((rect.left + rect.width) <= windowWidth)
                && ((rect.top + rect.height) <= windowHeight)
            );

        }


        function fnIsVis(ele)
        {
            var inVpFull = isElementInViewport(ele);
            var inVpPartial = isElementPartiallyInViewport(ele);
            console.clear();
            console.log("Fully in viewport: " + inVpFull);
            console.log("Partially in viewport: " + inVpPartial);
        }


        // var scrollLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft,
        // var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;

    </script>

</head>
<body>

    <div style="display: block; width: 2000px; height: 10000px; background-color: green;">

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <div style="background-color: crimson; display: inline-block; width: 800px; height: 500px;" ></div>
        <div id="myele" onclick="fnIsVis(this);" style="display: inline-block; width: 100px; height: 100px; background-color: hotpink;">
        t
        </div>

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />

    </div>

    <!--
    <script type="text/javascript">

        var element = document.getElementById("myele");
        var watcher = scrollMonitor.create( element );

        watcher.lock();

        watcher.stateChange(function() {
            console.log("state changed");
            // $(element).toggleClass('fixed', this.isAboveViewport)
        });

    </script>
    -->
</body>
</html>
+28
25 сент. '14 в 12:54
источник

Существует плагин jQuery под названием inview, который выполняет задание

+25
03 мая '10 в 17:00
источник

См. источник verge, в котором используется getBoundingClientRect. Это нравится:

function inViewport (el) {

    var r, html;
    if ( !el || 1 !== el.nodeType ) { return false; }
    html = document.documentElement;
    r = el.getBoundingClientRect();

    return ( !!r 
      && r.bottom >= 0 
      && r.right >= 0 
      && r.top <= html.clientHeight 
      && r.left <= html.clientWidth 
    );

}

Возвращает true, если любая часть элемента находится в окне просмотра.

+24
14 сент. '12 в 5:49
источник

моей более короткой и быстрой версии.

function isElementOutViewport(el){
    var rect = el.getBoundingClientRect();
    return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
}

добавьте jsFiddle по необходимости https://jsfiddle.net/on1g619L/1/

+22
23 апр. '14 в 3:04
источник

Мне показалось, что проблема в том, что доступной функциональности не существует jQuery. Когда я наткнулся на решение Dan, я попробовал предоставить что-то для людей, которые любят программировать в стиле jQuery OO. Обязательно прокрутите страницу вверх и оставите надпись на коду Дэн. Его приятно и быстро и работает как прелесть для меня.

bada bing bada boom

$.fn.inView = function(){
    if(!this.length) return false;
    var rect = this.get(0).getBoundingClientRect();

    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );

};

//additional examples for other use cases
//true false whether an array of elements are all in view
$.fn.allInView = function(){
    var all = [];
    this.forEach(function(){
        all.push( $(this).inView() );
    });
    return all.indexOf(false) === -1;
};

//only the class elements in view
$('.some-class').filter(function(){
    return $(this).inView();
});

//only the class elements not in view
$('.some-class').filter(function(){
    return !$(this).inView();
});

Использование

$(window).on('scroll',function(){ 

    if( $('footer').inView() ) {
        // do cool stuff
    }

});
+19
02 авг. '15 в 13:40
источник

Я считаю, что принятый ответ здесь слишком сложный для большинства случаев использования. Этот код хорошо выполняет работу (используя JQuery) и различает полностью видимые и частично видимые элементы.

var element         = $("#element");
var topOfElement    = element.offset().top;
var bottomOfElement = element.offset().top + element.outerHeight(true);
var $window         = $(window);

$window.bind('scroll', function() {

    var scrollTopPosition   = $window.scrollTop()+$window.height();
    var windowScrollTop     = $window.scrollTop()

    if( windowScrollTop > topOfElement && windowScrollTop < bottomOfElement) {
       // Element is partially visible (above viewable area)
       console.log("Element is partially visible (above viewable area)");

    }else if( windowScrollTop > bottomOfElement && windowScrollTop > topOfElement ) {
        // Element is hidden (above viewable area)
       console.log("Element is hidden (above viewable area)");

    }else if( scrollTopPosition < topOfElement && scrollTopPosition < bottomOfElement ) {
        // Element is hidden (below viewable area)
        console.log("Element is hidden (below viewable area)");

    }else if( scrollTopPosition < bottomOfElement && scrollTopPosition > topOfElement ) {
        // Element is partially visible (below viewable area)
        console.log("Element is partially visible (below viewable area)");

    }else{
        // Element is completely visible
        console.log("Element is completely visible");
    }
});
+8
30 янв. '15 в 14:49
источник

http://www.appelsiini.net/projects/viewport

Отличный простой в использовании плагин, просто используйте: in-viewport

+7
14 дек. '12 в 1:30
источник

Я думаю, что это более функциональный способ сделать это. Ответ "Дан" не работает в рекурсивном контексте.

Эта функция решает проблему, когда ваш элемент находится внутри других прокручиваемых divs, проверяя любые уровни, рекурсивно верхние к тегу HTML, и останавливается в первом false.

/**
 * fullVisible=true only returns true if the all object rect is visible
 */
function isReallyVisible(el, fullVisible) {
    if ( el.tagName == "HTML" )
            return true;
    var parentRect=el.parentNode.getBoundingClientRect();
    var rect = arguments[2] || el.getBoundingClientRect();
    return (
            ( fullVisible ? rect.top    >= parentRect.top    : rect.bottom > parentRect.top ) &&
            ( fullVisible ? rect.left   >= parentRect.left   : rect.right  > parentRect.left ) &&
            ( fullVisible ? rect.bottom <= parentRect.bottom : rect.top    < parentRect.bottom ) &&
            ( fullVisible ? rect.right  <= parentRect.right  : rect.left   < parentRect.right ) &&
            isReallyVisible(el.parentNode, fullVisible, rect)
    );
};
+3
24 апр. '15 в 15:12
источник

Все ответы, которые я встречал здесь, проверяют только, находится ли элемент внутри текущего окна просмотра. Но этот не означает, что он виден.
Что, если данный элемент находится внутри div с переполненным контентом, и он прокручивается вне поля зрения?

Чтобы решить эту проблему, вам нужно будет проверить, содержит ли элемент все родители.
Мое решение делает именно это:

Он также позволяет указать, какая часть элемента должна быть видимой.

Element.prototype.isVisible = function(percentX, percentY){
    var tolerance = 0.01;   //needed because the rects returned by getBoundingClientRect provide the position up to 10 decimals
    if(percentX == null){
        percentX = 100;
    }
    if(percentY == null){
        percentY = 100;
    }

    var elementRect = this.getBoundingClientRect();
    var parentRects = [];
    var element = this;

    while(element.parentElement != null){
        parentRects.push(element.parentElement.getBoundingClientRect());
        element = element.parentElement;
    }

    var visibleInAllParents = parentRects.every(function(parentRect){
        var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
        var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
        var visiblePercentageX = visiblePixelX / elementRect.width * 100;
        var visiblePercentageY = visiblePixelY / elementRect.height * 100;
        return visiblePercentageX + tolerance > percentX && visiblePercentageY + tolerance > percentY;
    });
    return visibleInAllParents;
};

Это решение игнорировало тот факт, что элементы могут быть не видны из-за других фактов, таких как opacity: 0.

Я тестировал это решение в Chrome и Internet Explorer 11.

+3
23 июн. '16 в 17:47
источник

Основываясь на вышеприведенном решении @dan (qaru.site/questions/10631/...), я решил выполнить очистку, так что использовать его несколько раз на одной странице проще:

$(function() {

  $(window).on('load resize scroll', function() {
    addClassToElementInViewport($('.bug-icon'), 'animate-bug-icon');
    addClassToElementInViewport($('.another-thing'), 'animate-thing');
    // 👏 repeat as needed ...
  });

  function addClassToElementInViewport(element, newClass) {
    if (inViewport(element)) {
      element.addClass(newClass);
    }
  }

  function inViewport(element) {
    if (typeof jQuery === "function" && element instanceof jQuery) {
      element = element[0];
    }
    var elementBounds = element.getBoundingClientRect();
    return (
      elementBounds.top >= 0 &&
      elementBounds.left >= 0 &&
      elementBounds.bottom <= $(window).height() &&
      elementBounds.right <= $(window).width()
    );
  }

});

Способ, которым я пользуюсь, заключается в том, что когда элемент прокручивается в поле зрения, я добавляю класс, который запускает анимацию ключевого кадра css. Это довольно просто и особенно хорошо работает, когда у вас есть 10+ вещей, которые можно условно охарактеризовать на странице.

Надеюсь, что это поможет!

+2
26 дек. '14 в 21:00
источник

Зависит от того, что вы подразумеваете под видимым. Если вы имеете в виду, это в настоящее время отображается на странице, учитывая положение прокрутки, вы можете рассчитать ее на основе смещений элементов y и текущей позиции прокрутки.

+2
23 сент. '08 в 21:29
источник

Легкое и маленькое решение, которое сработало для меня.

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

$(window).on('scroll', function () {  

     var container = $('#sidebar');
     var containerHeight = container.height();
     var scrollPosition = $('#row1').offset().top - container.offset().top;

     if (containerHeight < scrollPosition) {
         console.log('not visible');
     } else {
         console.log('visible');
     }
})
+1
19 июн. '17 в 10:49
источник

Здесь мое решение, оно будет работать, если элемент скрыт внутри контейнера с прокруткой.

Здесь демо (попробуйте изменить размер окна)

var visibleY = function(el){
    var top = el.getBoundingClientRect().top, rect, el = el.parentNode;
    do {
        rect = el.getBoundingClientRect();
        if (top <= rect.bottom === false)
            return false;
        el = el.parentNode;
    } while (el != document.body);
    // Check its within the document viewport
    return top <= document.documentElement.clientHeight;
};

Мне нужно было проверить, видимо ли оно по оси Y (для прокрутки ajax load больше функций записи).

+1
07 февр. '14 в 11:39
источник

Вот функция, которая сообщает, является ли элемент видимым в текущем окне просмотра родительского элемента:

function inParentViewport(el, pa) {
    if (typeof jQuery === "function"){
        if (el instanceof jQuery)
            el = el[0];
        if (pa instanceof jQuery)
            pa = pa[0];
    }

    var e = el.getBoundingClientRect();
    var p = pa.getBoundingClientRect();

    return (
        e.bottom >= p.top &&
        e.right >= p.left &&
        e.top <= p.bottom &&
        e.left <= p.right
    );
}
0
28 сент. '18 в 10:01
источник

Лучшее решение:

function getViewportSize(w) {
    var w = w || window;
    if(w.innerWidth != null) return {w:w.innerWidth, h:w.innerHeight};
    var d = w.document;
    if (document.compatMode == "CSS1Compat") {
        return {
            w: d.documentElement.clientWidth,
            h: d.documentElement.clientHeight
        };
    }
    return { w: d.body.clientWidth, h: d.body.clientWidth };
}
function isViewportVisible(e) {
    var box = e.getBoundingClientRect();
    var height = box.height || (box.bottom - box.top);
    var width = box.width || (box.right - box.left);
    var viewport = getViewportSize();
    if(!height || !width) return false;
    if(box.top > viewport.h || box.bottom < 0) return false;
    if(box.right < 0 || box.left > viewport.w) return false;
    return true;    
}
0
08 февр. '13 в 8:57
источник

У меня был тот же вопрос, и я понял, используя getBoundingClientRect(). Этот код полностью "общий" и должен быть написан только один раз для его работы (вам не нужно записывать его для каждого элемента, который вы хотите знать, в окне просмотра). Этот код проверяет только, находится ли он вертикально в окне просмотра не горизонтально. В этом случае переменные (массивы) "элементы" содержат все элементы, которые вы проверяете, чтобы они были вертикально в окне просмотра, поэтому хватайте любые элементы, которые вы хотите где угодно, и храните их там. Цикл "for" циклически проходит через каждый элемент и проверяет, находится ли он вертикально в окне просмотра. Этот код выполняет каждый раз, который прокручивает пользователь! Если верхняя часть getBoudingClientRect() меньше 3/4, то окно просмотра (элемент составляет одну четверть в окне просмотра), он регистрируется как "в окне просмотра". Поскольку код является общим, вам нужно знать, какой элемент находится в окне просмотра. Чтобы узнать это, вы можете определить его по пользовательскому атрибуту, node имя, идентификатор, имя класса и т.д. Вот мой код (скажите, если он не работает, он был протестирован в IE 11, FireFox 40.0.3, Chrome версии 45.0.2454.85 m, Opera 31.0.1889.174 и Edge с Windows 10, [еще не Safari])...

//scrolling handlers...
window.onscroll = function(){
  var elements = document.getElementById('whatever').getElementsByClassName('whatever');
  for(var i = 0; i != elements.length; i++)
  {
   if(elements[i].getBoundingClientRect().top <= window.innerHeight*0.75 && elements[i].getBoundingClientRect().top > 0)
   {
      console.log(elements[i].nodeName + ' ' + elements[i].className + ' ' + elements[i].id + ' is in the viewport; proceed with whatever code you want to do here.');
   }
};

Надеюсь, это поможет кому-то: -)

0
13 сент. '15 в 13:59
источник

Проверяет, является ли элемент хотя бы частично отображаемым (вертикальный размер):

function inView(element) {
                var box = element.getBoundingClientRect();
                return inViewBox(box);
}

function inViewBox(box) {
                return ((box.bottom < 0) || (box.top > getWindowSize().h)) ? false : true;
}


function getWindowSize() { 
        return { w: document.body.offsetWidth || document.documentElement.offsetWidth || window.innerWidth, h: document.body.offsetHeight || document.documentElement.offsetHeight || window.innerHeight} 
}
0
02 янв. '15 в 12:17
источник

Это мой один лайнер (требуется jQuery):

let isInView = (elem)=>(($(elem).offset().top + $(elem).height() - 800 <= $(window).scrollTop() + $(window).height()) && ($(elem).offset().top + 600 >= $(window).scrollTop()));

Функция возвращает true, если элемент находится в представлении, а false - если нет. Он выдает ошибку, если элемент не существует.

Вы можете вызвать функцию следующим образом: isInView($('#my-div'))

-1
04 дек. '17 в 19:16

Я использую эту функцию (она только проверяет, является ли y незашифрованным, поскольку большую часть времени x не требуется)

function elementInViewport(el) {
    var elinfo = {
        "top":el.offsetTop,
        "height":el.offsetHeight,
    };

    if (elinfo.top + elinfo.height < window.pageYOffset || elinfo.top > window.pageYOffset + window.innerHeight) {
        return false;
    } else {
        return true;
    }

}
-1
13 янв. '17 в 6:57
источник

Для подобной задачи мне действительно понравился этот смысл, который предоставляет polyfill для scrollIntoViewIfNeeded().

Все необходимые Кунг-фу, необходимые для ответа, находятся внутри этого блока:

var parent = this.parentNode,
    parentComputedStyle = window.getComputedStyle(parent, null),
    parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')),
    parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')),
    overTop = this.offsetTop - parent.offsetTop < parent.scrollTop,
    overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight),
    overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft,
    overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth),
    alignWithTop = overTop && !overBottom;

this относится к элементу, который вы хотите знать, если он есть i.e. overTop или overBottom - просто должен получить дрейф...

-2
14 мар. '16 в 13:14
источник

Мне нужно решение jQuery, которое является простым (только для проверки вертикальной прокрутки), поэтому я изменил код Адама Рехалса. В этом примере щелкните все кнопки в окне просмотра, проверяя 5 раз в секунду. (кнопки становятся отключенными при нажатии на кнопку btw)

$(function () {
    var loadButtons = $('.btn-load-more');

    function clickButtonsIfInViewport() {
        loadButtons.each(function () {
            var element = $(this);
            var elementOffset = element.offset();
            var elementTop = elementOffset.top;
            var elementBottom = elementOffset.top + element.outerHeight(true);

            var windowTop = $window.scrollTop();
            var windowBottom = windowTop + $window.height();

            if (windowTop > elementBottom || windowBottom < elementTop) {
                return;
            }

            element.click();
        });
    }

    setInterval(clickButtonsIfInViewport, 200);
});
-2
26 мая '16 в 8:20
источник

Посмотрите другие вопросы по меткам или Задайте вопрос