4

I have got a method to check whether an element is in view or not from How to tell if a DOM element is visible in the current viewport?. And trying to run the test to check whether elements are in view or not

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

But it returns true for all the elements who are below parent element's client height value. What changes are required to make this work. Fiddle

Community
  • 1
  • 1
Exception
  • 8,111
  • 22
  • 85
  • 136

1 Answers1

3

The following answer from that question works if you remove the jQuery cruft (which throws an error if you don't have a global variable called jQuery):

[deleted code]

Edit

Based on various answers from the link in the OP, following seems to work, only lightly tested but it works in the OP's fiddle. It checks if an element is inside its parents and the viewport. Hopefully the comments are sufficient:

// Return true if an element overlaps its parents and the viewport
function isVisible(element) {
  return isInParents(element) && isInViewport(element);
}

// Return true if an element overlaps its parents
function isInParents(el) {
  var rect = el.getBoundingClientRect(),
      rectP,
      visible = true;

  while (el && el.parentNode && el.parentNode.getBoundingClientRect && visible) {
    el = el.parentNode;
    rectP = el.getBoundingClientRect();
    visible = rectInRect(rectP, rect);
  }
  return visible;
}

// Return true if element overlaps the viewport
function isInViewport (element) {

    var rect = element.getBoundingClientRect();

    return rectInRect({top:0, left:0,
                       bottom: window.innerHeight || document.documentElement.clientHeight,
                       right:  window.innerWidth  || document.documentElement.clientWidth
                      }, rect);
}

// Return true if r1 overlaps r0
function rectInRect(r0, r1) {
  return r1.top    < r0.bottom &&
         r1.bottom > r0.top    &&
         r1.left   < r0.right  &&
         r1.right  > r0.left;
}

As to whether the element is visible or not depends on other factors, such as whether overlapping elements are hidden or not, or whether some other non–ancestor element is positioned on top, etc. Those conditions can be checked for but it becomes less and less efficient the more you have to check.

If thoroughness and performance matter, create a binary tree index of the spatial location of all elements on the page and update it as you go. Creating the index is slow, but checking position will be hugely faster.

Community
  • 1
  • 1
RobG
  • 142,382
  • 31
  • 172
  • 209
  • Thanks for an answer. But please check here http://jsfiddle.net/cAY8c/50/ It makes green even for elements who are not in view. – Exception Sep 11 '14 at 05:16
  • There is a comment that that answer has the maths wrong, I guess I need to check it now… Oh, now I see. This one looks at the viewport, whereas your element is inside a parent. Hmm… that gets more complex. – RobG Sep 11 '14 at 05:19
  • You are awesome.. It worked fine for my use case. I even checked it with different zoom levels of browser. – Exception Sep 11 '14 at 06:15
  • @RobG A small test case, isInViewport(element); returns false when event height is bigger than its parent DIV (http://jsfiddle.net/cAY8c/61/) when two elements are in view taking 50% each. So removing isInViewport just works fine. – redV Sep 11 '14 at 06:38
  • I updated my post a while ago to use my logic for rect in rect for the viewport as well as parents. Updated the Fiddle too so now that case seems to work properly if the viewport test is included. I tested the 50/50 case originally and it seemed to work… The viewport logic is pretty simple, maybe it should be before the parent one. – RobG Sep 11 '14 at 07:02