Search code examples
javascriptyoutube

How to get a lazyloaded YouTube video to play automatically?


I've written a script that creates a lazy-loaded youtube video. When clicked on, the image goes away and I've built into the script that autoplay=1 is appended to the URL. However, it isn't working and I'm unsure what direction to take.

It doesn't seem to be working all the time in the SO embed, so here it is on Codepen as well.

//youtube embed script
function playYouTube() {
  // Iterate over every YouTube container you may have
  let YouTubeContainers = document.querySelectorAll('.youtube-embed');

  for (let i = 0; i < YouTubeContainers.length; i++) {
    let container = YouTubeContainers[i];
    let imageSource =
      "https://img.youtube.com/vi/" +
      container.dataset.videoId +
      "/0.jpg";

    // Load the Thumbnail Image asynchronously
    let image = new Image();
    image.src = imageSource;
    image.addEventListener("load", function () {
      const altText = container.dataset.alt
      container.appendChild(image);
      image.setAttribute('loading', 'lazy');
      image.classList.add('lazy');

      if (altText && altText.length) {
        image.setAttribute('alt', altText);
        container.removeAttribute('data-alt');
      } else {
        image.setAttribute('alt', 'Youtube video cover');
      }
    });

    // When the user clicks on the container, load the embedded YouTube video
    container.addEventListener("click", function () {
      let iframe = document.createElement("iframe");

      iframe.setAttribute("frameborder", "0");
      iframe.setAttribute("allowfullscreen", "");
      iframe.setAttribute(
        "allow",
        "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
      );
      // Important: add the autoplay GET parameter, otherwise the user would need to click over the YouTube video again to play it
      iframe.setAttribute(
        "src",
        `https://www.youtube.com/embed/${this.dataset.videoId}?rel=0&showinfo=0&autoplay=1`
      );

      // Clear Thumbnail and load the YouTube iframe
      this.innerHTML = "";
      this.appendChild(iframe);
    });
  };
}

var doesYtExist = (function () {
  let YouTubeContainers = document.querySelector('.youtube-embed');

  YouTubeContainers ? playYouTube() : console.log('No YouTube videos here.');
})();
.video-container {
  max-width: 760px;
  margin: 48px auto 0;
  width: 100%;
}

.youtube-embed,
.youtube embed,
.youtube iframe {
  width: 100%;
  max-height: 100%;
}
.youtube-embed {
  position: relative;
  padding-top: 56%;
  overflow: hidden;
  cursor: pointer;
}
.youtube-embed img {
  width: 100%;
  top: -16.84%;
  left: 0;
}
.youtube-embed iframe {
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
}
.youtube-embed iframe,
.youtube-embed img {
  position: absolute;
}
.youtube-embed button.embed-video__play {
  background: url("https://www.nextiva.com/assets/svg/play-button.svg")
      no-repeat center center,
    rgba(33, 33, 33, 0.8);
  background-size: 40%;
  background-position: 55%;
  border: 0;
  border-radius: 50%;
  position: absolute;
  transition: all 0.2s ease;
  -webkit-transition: background 0.2s;
  width: 16%;
  aspect-ratio: 1/1;
  height: auto;
  cursor: pointer;
  z-index: 10;
  display: flex;
  justify-content: center;
  align-items: center;
  top: 50%;
  left: 50%;
  transform: translate3d(-50%, -50%, 0);
}
.youtube-embed:hover button.embed-video__play,
.youtube-embed button.embed-video__play:focus,
.youtube-embed button.embed-video__play:focus-visible {
  background: url("https://www.nextiva.com/assets/svg/play-button.svg")
      no-repeat center center,
    #005fec;
  background-size: 40%;
  background-position: 55%;
  box-shadow: 0 0 0 4px #fff !important;
  outline: none;
}
<div class="video-container">
  <div class="youtube-embed" data-video-id="HyH17vyLmuI">
    <button class="embed-video__play" aria-label="play Trace Advisors success story video"></button>
  </div>  
</div>


Solution

  • You can only autoplay it muted, by adding &mute=1 to the iframe url. Otherwise, it just won't work.

    I'ts been like that since 2019 (see this answer), although there's no official documentation mentioning that.

    I did try a trick: first load the iframe with the &mute=1 parameter, but have an onload on the iframe that on first load removes that parameter. Unfortunately, this also doesn't work.