Masking an iframe with a porose div.

This experiment puts a div on top of an iframe, and pokes holes on it, so the iframe only receives mouse events where relevant.

by David Iglesias

HTML

<div class="yt-iframe-container">
  <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/lJIrF4YjHfQ?si=V4Qja3ZHjPMymySh&amp;rel=0&amp;controls=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen id="embeddedvideo"></iframe>
  <div class="yt-iframe-mask">
    <!-- <img src="https://picsum.photos/560/315" /> -->
  </div>
</div>

CSS

.yt-iframe-container {
  position: relative;
  width: 560px;
  height: 315px;
}

JavaScript

const element = document.querySelector('.yt-iframe-mask');
// Cover the iframe completely
element.style.position = 'absolute';
element.style.inset = 0;
// Optional, so the effect is visible. Remove.
element.style.background = 'rgba(0, 127, 0, .5)';

const width = element.clientWidth;
const height = element.clientHeight;
// The holes for the Play Button and other UI elements (winding ↩️)
const holes = [
  getRectangleHole(0, 0, 290, 60), // Video Title
  getRectangleHole(470, 5, 80, 60), // Copy link
  getRectangleHole(240, 130, 80, 55), // Play Button
  getRectangleHole(420, 263, 140, 47), // Watch on YT/play bar
]
// The actual SVG that contains the holes (winding ↪️)
const path = `M 0 0 v${height} h${width} V0 H0 ${holes.join(' ')} Z`;
// Punch the hole
element.style.clipPath = `path('${path}')`;

// Returns a rectangle path at x, y with width w and height h. Wound clockwise (↩️).
function getRectangleHole(x, y, w, h) {
  return `M ${x} ${y} h${w} v${h} h${-w} v${-h}`
}