How to Tell If a Dom Element Is Visible in the Current Viewport

How can I tell if a DOM element is visible in the current viewport?

Update: Time marches on and so have our browsers. This technique is no longer recommended and you should use Dan's solution if you do not need to support version of Internet Explorer before 7.

Original solution (now outdated):

This will check if the element is entirely visible in the current viewport:

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

You could modify this simply to determine if any part of the element is visible in the viewport:

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

Check if element is visible in DOM

According to this MDN documentation, an element's offsetParent property will return null whenever it, or any of its parents, is hidden via the display style property. Just make sure that the element isn't fixed. A script to check this, if you have no position: fixed; elements on your page, might look like:

// Where el is the DOM element you'd like to test for visibility
function isHidden(el) {
return (el.offsetParent === null)
}

On the other hand, if you do have position fixed elements that might get caught in this search, you will sadly (and slowly) have to use window.getComputedStyle(). The function in that case might be:

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

Option #2 is probably a little more straightforward since it accounts for more edge cases, but I bet its a good deal slower, too, so if you have to repeat this operation many times, best to probably avoid it.

How to check if element is visible after scrolling?

This should do the trick:

function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();

var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();

return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

Simple Utility Function
This will allow you to call a utility function that accepts the element you're looking for and if you want the element to be fully in view or partially.

function Utils() {

}

Utils.prototype = {
constructor: Utils,
isElementInView: function (element, fullyInView) {
var pageTop = $(window).scrollTop();
var pageBottom = pageTop + $(window).height();
var elementTop = $(element).offset().top;
var elementBottom = elementTop + $(element).height();

if (fullyInView === true) {
return ((pageTop < elementTop) && (pageBottom > elementBottom));
} else {
return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
}
}
};

var Utils = new Utils();

Usage

var isElementInView = Utils.isElementInView($('#flyout-left-container'), false);

if (isElementInView) {
console.log('in view');
} else {
console.log('out of view');
}

How to tell if an element is visible in the viewport AND takes up the entire viewport?

You'll need to adjust the code a bit, but this works perfectly using a tiny bit of jQuery:

$(window).resize(function () {
myFun.elementBiggerThanViewportCallback();
});

myFun.elementBiggerThanViewport = function (el) {

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

var rect = el.getBoundingClientRect();

return (
rect.top <= 0 &&
rect.bottom >= (window.innerHeight || document.documentElement.clientHeight)
);
}

elementBiggerThanViewportCallback = function (el) {
var ifBigger = tabccordion.elementBiggerThanViewport(el);
// Do stuff here.
}

How to tell if a DOM element is displayed?

From a quick test in Firefox, it looks like the size and position properties (clientWidth, offsetTop etc.) all return 0 when an element is hidden by a parent being display:none.

Check if element is partially in viewport

Late answer, but about a month ago I wrote a function that does exactly that, it determines how much an element is visible measured in percent in the viewport. Ive tested it in chrome, firefox, ie11, ios on iphone/ipad. The function returns true when X percent (as a number from 0 to 100) of the element is visible. Only determines if the measurements of the element are visible and not if the element is hidden with opacity, visibility etc..

const isElementXPercentInViewport = function(el, percentVisible) {
let
rect = el.getBoundingClientRect(),
windowHeight = (window.innerHeight || document.documentElement.clientHeight);

return !(
Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-rect.height) * 100)) < percentVisible ||
Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100) < percentVisible
)
};

Check if an element is visible on screen

Here is a script returning a promise using the new IntersectionObserver API for checking whether or not an element is actually visible in the viewport:

function isVisible(domElement) {
return new Promise(resolve => {
const o = new IntersectionObserver(([entry]) => {
resolve(entry.intersectionRatio === 1);
o.disconnect();
});
o.observe(domElement);
});
}

Which you can use in your code:

const visible = await isVisible(document.querySelector('#myElement'));
console.log(visible);

how to know if an element is visible to the user?

Before using a 3rd party library, I would take a look at Intersection Observer.

The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.

Support is pretty good outside of Safari, though there is a polyfill. I don't typically advocate using polyfills unless the feature being polyfilled drastically simplifies web development. In this case, I think Intersection Observer is worth the polyfill. Before Observer, the hoops one needed to jump through to create a complex application with many scroll point intersection events is a huge bummer.

Here's a demo taken from here.

var statusBox = document.getElementById("statusBox");var statusText = document.getElementById("statusText");
function handler(entries, observer) { for (entry of entries) { statusText.textContent = entry.isIntersecting;
if (entry.isIntersecting) { statusBox.className = "yes"; } else { statusBox.className = "no"; } }}
/* By default, invokes the handler whenever: 1. Any part of the target enters the viewport 2. The last part of the target leaves the viewport */
let observer = new IntersectionObserver(handler);observer.observe(document.getElementById("target"));
html {  height: 200%;  min-height: 400px;  text-align: center;  font-family: sans-serif;  padding-top: 3.5em;}
#viewport { position: fixed; top: 0; left: 0; bottom: 0; right: 0; color: #aaa; font-weight: bold; font-size: 20vh; border: 8px dashed #aaa; padding-top: 40vh; margin: 0; user-select: none; cursor: default;}
#target { background-color: #08f; display: inline-block; margin: 100vh auto 100vh; color: white; padding: 4em 3em; position: relative;}
#statusBox { position: fixed; top: 0; left: 1em; right: 1em; font-family: monospace; padding: 0.5em; background-color: #ff8; border: 3px solid #cc5; opacity: .9;}
#statusBox.yes { background: #8f8; border-color: #5c5;}
#statusBox.no { background: #f88; border-color: #c55;}
<p id="viewport">Viewport</p>
<p>Scroll down...<p>
<div id="target">Target</div>
<p id="statusBox"> isIntersecting === <span id="statusText">unknown</span></p>


Related Topics



Leave a reply



Submit