문제

이 있는 효율적인 방법을 말하는 경우 DOM 요소(HTML 문서)는 현재 표시(에 나타납니다 뷰포트)?

(질문을 참조하 Firefox)

도움이 되었습니까?

해결책

업데이트: 시간은 행진하고 브라우저가 있습니다. 이 기술은 더 이상 권장되지 않습니다 아래에서 @dan의 솔루션을 사용해야합니다 (https://stackoverflow.com/a/7557433/5628) 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
  );
}

다른 팁

지금 대부분의 브라우저 지원하다 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 HTML5 API 웹 페이지가있는 탭이 활성화되어 표시되는지 관리하는 경우.

TODO :이 방법은 두 가지 상황을 처리하지 않습니다.

업데이트

최신 브라우저에서는 교차 관찰자 API 다음과 같은 이점을 제공합니다.

  • 스크롤 이벤트를 듣는 것보다 더 나은 성능
  • 크로스 도메인 iframes에서 작동합니다
  • 요소가 다른 요소를 방해/교차하는지 알 수 있습니다.

Intersection Observer는 본격적인 표준으로가는 길에 있으며 이미 Chrome 51+, Edge 15+ 및 Firefox 55+에서 지원되고 있으며 Safari를 위해 개발 중입니다. 또한 a 폴리 필 사용 가능.


이전 답변

몇 가지 문제가 있습니다 Dan이 제공 한 답변 그것은 어떤 상황에서는 부적합한 접근 방식이 될 수 있습니다. 이러한 문제 중 일부는 하단 근처의 답변에서 그의 코드가 다음과 같은 요소에 대해 잘못된 긍정적 인 입장을 줄 것이라고 지적합니다.

  • 테스트중인 다른 요소 앞에 숨겨져 있습니다.
  • 부모 또는 조상 요소의 가시 영역 외부
  • 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's 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 작업 초안 사양의 일부이며 최소한 6 세 이하에 지원됩니다. 대부분 데스크탑 브라우저는 오랫동안 (완벽하게는 아니지만). 보다 이 함수에 대한 퀴크 스 모드 자세한 내용은.

contains() 요소가 다시 반환되는지 확인하는 데 사용됩니다 document.elementFromPoint() 가시성을 테스트하는 요소의 자식 노드입니다. 반환 된 요소가 동일한 요소 인 경우에도 사실을 반환합니다. 이것은 단지 수표를 더욱 강력하게 만듭니다. 모든 주요 브라우저에서 지원되며 Firefox 9.0은 마지막으로 추가되었습니다. 오래된 Firefox 지원은이 답변의 역사를 확인하십시오.

가시성을 위해 요소 주변의 더 많은 점을 테스트하려면 (예 : 요소가 50%이상으로 덮여 있지 않도록하기 위해 답의 마지막 부분을 조정하는 데 많은 시간이 걸리지 않습니다. 그러나 모든 픽셀을 점검하여 100% 가시적인지 확인하면 매우 느릴 수 있습니다.

나는 시도했다 댄의 대답 하지만 경계를 결정하는 데 사용되는 대수는 요소가 뷰포트 크기와 뷰포트 내부에 있어야한다는 것을 의미합니다. 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() */;
}

공공 서비스 :
올바른 계산 (요소가> 특히 휴대폰 화면에서 window)과 올바른 jQuery 테스트를받은 Dan의 답변 및 IselementParticalliceInviewport 추가 :

그건 그렇고, 차이점 Window.innerWidth와 Document.DocumentElement.clientWidth 사이에 ClientWidth/ClientHeight에는 Scrollbar가 포함되어 있지 않으며 Window.InnerWidth/Height가합니다.

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>

jQuery 플러그인이 호출됩니다 Inview 그것은 일을합니다

소스를 참조하십시오 가장자리, 사용하는 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 만약에 어느 요소의 일부는 뷰포트에 있습니다.

내 짧고 빠른 버전.

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/

나는 그것이 없다는 것이 문제를 발견했다 jQuery 사용 가능한 기능의 중심 버전. 내가 만났을 때 댄의 해결책 나는 프로그램을 좋아하는 사람들에게 무언가를 제공 할 수있는 기회를 감시했다. jQuery 우 스타일. 댄의 코드에 위로 스크롤하고 업 투표를 남겨 두십시오. 그것의 멋지고 snappy이며 나를위한 매력처럼 작동합니다.

바다 빙 바다 붐

$.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
    }

});

여기서 수용된 답변은 대부분의 사용 사례에 지나치게 복잡하다는 것을 알았습니다. 이 코드는 작업을 잘 수행하고 (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");
    }
});

내가 여기서 만난 모든 답변은 요소가 있는지 확인합니다. 현재 뷰포트 내부에 위치합니다. 그러나 그것은 그것이 보인다는 의미는 아닙니다.
주어진 요소가 흐르는 콘텐츠가있는 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 에서이 솔루션을 테스트했습니다.

새로운 교차 관찰자 API 이 질문을 매우 직접적으로 다룹니다.

이 솔루션은 Safari, Opera 및 IE와 같이 폴리 필이 필요합니다. (폴리 필이 용액에 포함되어 있습니다).

이 솔루션에는 대상 (관찰) 인 상자가 있습니다. 볼 때, 헤더 상단의 버튼은 숨겨져 있습니다. 상자가보기를 떠나면 표시됩니다.

const buttonToHide = document.querySelector('button');

const hideWhenBoxInView = new IntersectionObserver((entries) => {
  if (entries[0].intersectionRatio <= 0) { // If not in view
    buttonToHide.style.display = "inherit";
  } else {
    buttonToHide.style.display = "none";
  }
});

hideWhenBoxInView.observe(document.getElementById('box'));
header {
  position: fixed;
  top: 0;
  width: 100vw;
  height: 30px;
  background-color: lightgreen;
}

.wrapper {
  position: relative;
  margin-top: 600px;
}

#box {
  position: relative;
  left: 175px;
  width: 150px;
  height: 135px;
  background-color: lightblue;
  border: 2px solid;
}
<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<header>
  <button>NAVIGATION BUTTON TO HIDE</button>
</header>
  <div class="wrapper">
    <div id="box">
    </div>
  </div>

나는 이것이 더 기능적인 방법이라고 생각합니다. Dan의 답변은 재귀적인 맥락에서 작동하지 않습니다.

이 기능은 요소가 다른 내부에있는 경우 문제를 해결하여 HTML 태그의 재귀 적으로 상단을 테스트하고 첫 번째 거짓으로 중지됩니다.

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

위의 @Dan의 솔루션을 기반으로 (https://stackoverflow.com/a/7557433/5628), 구현을 정리하여 구현을 여러 번 사용하여 동일한 페이지에서 여러 번 사용하는 것이 더 쉽습니다.

$(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 개 이상의 것들이있을 때 특히 잘 작동합니다.

도움이되기를 바랍니다!

내 솔루션은 다음과 같습니다. 스크롤 가능한 컨테이너 안에 요소가 숨겨져있는 경우 작동합니다.

여기 데모가 있습니다 (창을 다시 크기를 조정 해보세요)

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 더 많은 레코드 기능을로드하는 경우).

나를 위해 일한 쉽고 작은 솔루션.

예시 오버플로 스크롤이있는 부모 요소에서 요소가 표시되는지 확인하고 싶습니다.

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

더 나은 해결책 :

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

요소가 적어도 부분적으로 볼 수 있는지 확인합니다 (수직 차원) :

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

나도 같은 질문과 그것을 알아 냈어를 사용하여 getBoundingClientRect().이 코드는 완전히'일반'만 작성되어야 합니다면 그것을 위해 작업(하지 않아 그것을 밖으로 작성 각 요소에 대해 알고 싶은 뷰포트에서).이 코드만 검사하는 경우에 수직으로서 뷰포트 지 않을 수평으로.이 경우에는 변수(array)'요소는'모두 보유하고 있는 요소 점검을 수직으로 뷰포트에서,그래서 어떤 요소가 당신이 원하는 어디서나 저장합니다.는'루',루프를 통해 각각의 요소와 요소를 확인하는 경우에 수직으로 표시된다는 것입니다.이 코드는 실행 모든 시간 사용자가 스크롤!는 경우 getBoudingClientRect().최고보 3/4 뷰포트(요소 중 하나입 쿼터 뷰포트에서),등록으로'는 뷰포트에서'.이 코드는 일반적인,당신은 알고 싶은 것입니다'를'요소가에 호텔이 있습니다.을 알아내는 것을 확인할 수 있습여 사용자 지정 특성,노드 이름,id,클래스 이름을 더 있습니다.여기에는 나의 코드(말 그것이 작동하지 않는 경우,그것은에서 테스트되었습니다 IE11,FireFox40.0.3,크롬 버전 45.0.2454.85m,오페라 31.0.1889.174,그리고 가장자리로 윈도우 10,[지 않은 사파리 아직])...

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

희망이 누군가가 도움이 됩:-)

다음은 요소가 현재 뷰포트에 표시되어 있는지 알려주는 기능입니다. 부모의 요소:

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

IMO를 얻을 수있는만큼 더 간단합니다.

function isVisible(elem) {
  var coords = elem.getBoundingClientRect();
  return Math.abs(coords.top) <= coords.height;
}

이 기능을 사용합니다 (대부분 x가 필요하지 않기 때문에 y가 삽입 된 경우에만 확인합니다).

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

}

비슷한 도전을 위해 나는 정말로 즐겼습니다 이 요점 폴리 필을 노출시킵니다 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 IE인지 알고 싶은 요소를 나타냅니다. overTop 또는 overBottom - 드리프트를 가져와야합니다 ...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top