'Can an iframe check if itself is in viewport or not?
I'm creating an iframe with a small HTML5 video. the video shouldn't start playing unless the iframe is in the viewport.
I noticed that this isn't as easy as I would like since the iframe is like a sandboxed environment. Is it even possible for an iframe to know if it is in the viewport?
Solution 1:[1]
Checking whether an element is in the viewport
Here you can find a nice implementation for checking whether an element is in the viewport:
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
Reaching the parent window
Inside the iframe you can reach the parent window like this:
if (window.parent.isInViewport(document.querySelector('iframe'))) {
//do something
}
(in the above I'm searching for the first iframe in the parent window for the sake of simplicity, you might need to change your selector)
Yet, modern browsers only allow this kind of communication if the page the iframe points to is of the same domain the main page points to. If the two pages are of different domains, then modern browsers will throw a CORSS error.
You can have a messaging between a main page and the page loaded into the iframe as an alternative, but for that purpose the developers of the main page need to cooperate.
Solution 2:[2]
If the IFRAME source attribute "src" is executed in the same domain, you can do it but if the IFRAME take the src to a cross domain you need to be authorised to do it from the server where the file is hosted by configuring the CORS acceptation from your domain.
Solution 3:[3]
You can use IntersectionObserver to monitor if the iframe enters viewport. The code is pretty simple and clean if you go this way.
Here is a quick example of showing a youtube video on and off based on if the iframe is inside viewport.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.container {
display: flex;
flex-direction: column;
gap: 1rem;
align-items: flex-start;
}
.box {
background-color:lightblue;
color: white;
font-size: 4rem;
text-align: center;
margin: auto;
height: 200px;
width: 300px;
border: 1px solid black;
border-radius: 0.25rem;
padding: 0.5rem;
}
</style>
</head>
<body>
<div class="container">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">5</div>
<div class="box" id="divFrame">
<iframe></iframe>
</div>
<div class="box">6</div>
<div class="box">7</div>
<div class="box">8</div>
<div class="box">9</div>
<div class="box">10</div>
</div>
<script>
const iframeOserver = new IntersectionObserver((entries) => {
const iframe = entries[0].target.firstElementChild;
iframe.src = entries[0].isIntersecting ? "https://www.youtube.com/embed/tgbNymZ7vqY?autoplay=1&mute=1": "";
console.log("video " + (entries[0].isIntersecting ? "started" : "stopped"));
}, { threshold: 0.5});
iframeOserver.observe(document.getElementById("divFrame"));
</script>
</body>
</html>
I set the threshold of intersection to 50% (threshold: 0.5) in the above example. You can change it as you needed.
Please refer to the following link for details about IntersectionObserver: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Lajos Arpad |
| Solution 2 | |
| Solution 3 | ch_g |
