Play YouTube video on clicking placeholder without double click

Viewed 517

I'm using this Codepen to load YouTube video only on clicking the placeholder/thumbnail.

It's works, but requires two click to play the video in Chrome. (even though ?autoplay=1 is added).

I know that videos will be autoplayed only if it's muted or user has interacted with the site. In this case, user interacts by clicking the placeholder/thumbnail.

<iframe
  width="560"
  height="315"
  src="https://www.youtube.com/embed/Y8Wp3dafaMQ"
  srcdoc="<style>*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}</style><a href=https://www.youtube.com/embed/Y8Wp3dafaMQ?autoplay=1><img src=https://img.youtube.com/vi/Y8Wp3dafaMQ/hqdefault.jpg alt='Video The Dark Knight Rises: What Went Wrong? – Wisecrack Edition'><span>▶</span></a>"
  frameborder="0"
  allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
  allowfullscreen
  title="The Dark Knight Rises: What Went Wrong? – Wisecrack Edition"
        ></iframe>

Under the hood, this code uses srcdoc to link to the YouTube video from the image, e.g.: <a href="YOUTUBE_VIDEO"><img src="THUMBNAIL"/></a>).

3 Answers

Google Chrome has some issues nowadays with the playing of video's when they are not muted when you embed them in your HTML. I recommend using the API. This requires the use of JavaScript, but it also gives you more control. What I would do is have the preview image as an overlay and a custom button which, apart from starting the video, will hide the image and the button itself. Here is an example:

HTML

<div class="wrapper">
    <div id="ytplayer"></div>
    <img id="image-overlay" src="https://img.youtube.com/vi/Y8Wp3dafaMQ/hqdefault.jpg" alt="alt text">
    <button id="play">▶</button>
</div> 

JS

// Get the HTML element you need.
const imageOverlay = document.getElementById('image-overlay')
const playButton = document.getElementById('play')

// Add the event listener for the play button.
playButton.addEventListener('click', play)

// The function that is called when the button is clicked.
function play(e) {
  e.preventDefault();

  // Hide the overlay and button and start playing the video.
  playButton.style.display = 'none';
  imageOverlay.style.display = 'none';

  const tag = document.createElement('script');
  tag.src = "https://www.youtube.com/player_api";
  const firstScriptTag = document.getElementsByTagName('script')[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

  let player;
  window.onYouTubePlayerAPIReady = function () {
    player = new YT.Player('ytplayer', {
      height: '315',
      width: '560',
      videoId: 'Y8Wp3dafaMQ',
      events: {
        'onReady': onPlayerReady,
      },
      playerVars: {
        // 'controls': 0, // If you would like to hide the controls, uncomment this line.
      },
    });
  }

  function onPlayerReady() {
    player.playVideo();
  }
}

CSS

.wrapper {
    position: relative;
    width: 560px;
    height: 315px;
}

#image-overlay {
    position: absolute;
    object-position: center;
    height: 100%;
    object-fit: cover;
    width: 100%;
    top: 0;
    left: 0;
}

#play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 48px;
    line-height: 0;
    padding-left: 14px;
    width: 2em;
    height: 2em;
    color: white;
    border: none;
    border-radius: 50%;
    background-color: #323842;
}

#play:hover {
    cursor: pointer;
}

If you want to lazy load then you need to put the player on the page along with the thumbnail.

  • Put the player behind the thumbnail. So it will load till user clicks on thumbnail.
  • When user clicks the thumbnail, hide the thumbnail.
  • Then play the video.

We can use YouTube Player API to control the player. The API automatically creates iframe you don't have to create it. Note the API code needs to be on main page not in iframe.

Here is demo website: https://sg4v3.csb.app/ .
And corresponding codesandbox.
Note the difference between running the website separately and on sandbox page in an iframe. The sandbox editor doesn't give autoplay permission to the output iframe. That is why the code can never be demoed on Codepen, jsfiddle and other online editors.

Here is the code for ready reference. Copy it in local html file and run it in a browser:

<!DOCTYPE html>
<html>
<head>
  <style>
    * {
      padding: 0;
      margin: 0;
      overflow: hidden
    }

    html, body {
      height: 100%
    }

    img, span {
      position: absolute;
      width: 100%;
      top: 0;
      bottom: 0;
      margin: auto
    }

    span {
      height: 1.5em;
      text-align: center;
      font: 48px/1.5 sans-serif;
      color: white;
      text-shadow: 0 0 0.5em black
    }

    #wrapper {
      position: relative;
      width: fit-content;
      cursor: pointer;
    }

    #wrapper>#thumbnail {
      position: absolute;
      top: 0;
      left: 0;
      height: 100%;
      width: 100%;
    }
  </style>
</head>

<body>
  <h1 style="text-align: center;">My Website</h1>
  <div id="wrapper">
    <div id="thumbnail">
      <img src=https://img.youtube.com/vi/Y8Wp3dafaMQ/hqdefault.jpg
        alt='Video The Dark Knight Rises: What Went Wrong? – Wisecrack Edition'>
      <span>▶</span>
    </div>
    <!-- The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>
  </div>
  <script>
    //This code loads the IFrame Player API code asynchronously.
    var tag = document.createElement('script');
    tag.src = "https://www.youtube.com/iframe_api";
    var firstScriptTag = document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

    //This function creates an <iframe> (and YouTube player)
    //after the API code downloads.
    var player;
    let playerReady = false;
    let thumbnail = document.getElementById('thumbnail');
    function onYouTubeIframeAPIReady() {
      player = new YT.Player('player', {
        height: '390',
        width: '640',
        videoId: 'Y8Wp3dafaMQ',
        playerVars: {
          'playsinline': 1,
          'autoplay': 1
        },
        events: {
          'onReady': () => { playerReady = true; }
        }
      });
    }

    thumbnail.addEventListener('click', playVideo);
    async function playVideo() {
      if (!playerReady) {
        console.log('waiting...');
        await until(p => playerReady);
      }

      console.log('playing!');
      if (thumbnail)
        thumbnail.remove();
      player.playVideo();
    }

    function until(conditionFunction) {
      const poll = resolve =>
        conditionFunction() ? resolve() : setTimeout(_ => poll(resolve), 400);
      return new Promise(poll);
    }
  </script>
</body>

</html>


Don't put this code in StackOverflow snippet it won't work.

You are right!, It will autoplay with the sound off,

but by adding &mute=1 after autoplay=1

you wont have to double click.

I know you want the video to play once clicked on the thumbnail but it wont,

so why not just remove the thumbnail and show only the video so only 1 click is needed

Related