Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if element is half visible in the viewport with JavaScript?

I'm using the following function to check if an element is visible or not in the viewport :

function elementInViewport(el) {
  let top = el.offsetTop;
  let left = el.offsetLeft;
  const width = el.offsetWidth;
  const 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
  );
}

However, I want to check if an element is 50% visible in the viewport. So if half of it is only showing, the check should return true. I know this is possible using the Intersection Observer API, however that is not an option for me as I want this to be compatible with IE11.

like image 235
Ralph David Abernathy Avatar asked Sep 22 '20 19:09

Ralph David Abernathy


People also ask

How much of an element is visible in viewport?

So even if it's a part of a element but it covers the full height of the screen, it should be 100% in viewport.

Is element in viewport Javascript?

If an element is in the viewport, it's position from the top and left will always be greater than or equal to 0 . It's distance from the right will be less than or equal to the total width of the viewport, and it's distance from the bottom will be less than or equal to the height of the viewport.

How do you know if an element is visible in the screen during scrolling?

To know whether the element is fully visible in viewport, you will need to check whether top >= 0, and bottom is less than the screen height. In a similar way you can also check for partial visibility, top is less than screen height and bottom >= 0.


1 Answers

This test will work for one direction (either horizontal or vertical).

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

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

Note that the code that you copied to your question is not a good solution as it is very slow (and inaccurate). You should use getBoundingClientRect and you are done without any "manual" DOM traversal.

You can play around with this to see it in action:

function checkFifty() {
    var el = document.getElementById("element");
    var rect = el.getBoundingClientRect();

    console.log (
        // top
        rect.top + (rect.height/2) > 0 &&
        // left
        rect.left + (rect.width/2) > 0 &&
        // bottom
        rect.top + (rect.height/2) < (window.innerHeight || document.documentElement.clientHeight) &&
        // right
        rect.left + (rect.width/2) < (window.innerWidth || document.documentElement.clientWidth)
    );
}

function showCoordinates() {
    var el = document.getElementById("element");
    var rect = el.getBoundingClientRect();

    console.log(rect);
}
#buttons {
  position: fixed;
  top: 0px;
  left: 0px;
}
#container {
  width: 2000px;
  height: 2000px;
}
#element {
  margin: 800px;
  width: 200px;
  height: 200px;
  background-color: red;
}
<div id="buttons">
    <button onclick="showCoordinates()">coords</button>
    <button onclick="checkFifty()">check 50%</button>
    <p>scroll to the box and press the buttons. check the console output.</p>
</div>

<div id="container">
    <div id="element"></div>
</div>
like image 192
lupz Avatar answered Oct 07 '22 10:10

lupz