In this tutorial I’ll explain how to “lazy load” multiple embedded YouTube videos. Doing so will improve the performance of our initial page load, and hand some power over to the user.
Lazy Loading
Embedding a Youtube video has become a completely normal process for anyone involved with the web; copy, paste, done. However, pulling in an external resource like a Youtube video may slow down a web page’s load performance, especially if there are two or more videos embedded on the same page.
By embedding videos we request more than just a video file. A number of resources are fetched, including JavaScript files, a stylesheet, images, and advertisements. And as you can from the screenshot below, two Youtube videos equates to 22 HTTP requests with a total of 624kb downloaded. These numbers will climb as we embed more videos on the page.

So, instead of loading the Youtube video as soon as the page loads, we are going to pull and play the video when the user asks to do so. This method is popularly known as lazy loading–it will minimise the HTTP requests on initial page load, and ultimately improve the page’s performance.
Without further ado, let’s get started.
1. HTML Structure
We begin with building the HTML. This is straight forward; we’re using just two div
elements. The first div
will wrap around the embedded Youtube video, the second div
is nested in the first div
, and we’ll use it to shape the Play button to illustrate that this is a playable video.
<!-- (1) video wrapper --> <div class="youtube" data-embed="AqcjdkPMPJA"> <!-- (2) the "play" button --> <div class="play-button"></div> </div>
As you can see from the above code snippet, we have added a class
to these div
elements and a data-
attribute to the first div
to specify the ID of the Youtube video we’ll embed.
2. CSS
Next, we add the styles:
.youtube { background-color: #000; margin-bottom: 30px; position: relative; padding-top: 56.25%; overflow: hidden; cursor: pointer; } .youtube img { width: 100%; top: -16.84%; left: 0; opacity: 0.7; } .youtube .play-button { width: 90px; height: 60px; background-color: #333; box-shadow: 0 0 30px rgba( 0,0,0,0.6 ); z-index: 1; opacity: 0.8; border-radius: 6px; } .youtube .play-button:before { content: ""; border-style: solid; border-width: 15px 0 15px 26.0px; border-color: transparent transparent transparent #fff; } .youtube img, .youtube .play-button { cursor: pointer; } .youtube img, .youtube iframe, .youtube .play-button, .youtube .play-button:before { position: absolute; } .youtube .play-button, .youtube .play-button:before { top: 50%; left: 50%; transform: translate3d( -50%, -50%, 0 ); } .youtube iframe { height: 100%; width: 100%; top: 0; left: 0; }
These styles mainly deal with:
- Retaining the (flexible) video aspect ratio at 16:9, which is the recommended aspect ratio for a Youtube video. In doing so, we set the
padding-top
of the firstdiv
to 56.25%. This number is derived from dividing 9 by 16 and multiply the resultant to 100%. - Forming the second
div
to a play button and positioning it to the center of the firstdiv
. - Positioning the Youtube video image thumbnail that we will fetch and add in later through JavaScript.
At this point, we should see these div
elements begin to resemble a typical online video player, as follows:

3. JavaScript
Let’s write scripts to fetch the image thumbnail based on the Youtube ID added in the data-embed
attribute. Ultimately, it will also embed and play the video upon the user click.
Image Thumbnail
To start it off, we select the div
elements that will wrap the embedded video; the ones with theyoutube
class.
var youtube = document.querySelectorAll( ".youtube" );
Since we may have two or more Youtube videos, we will then have to iterate through each of the selected elements:
... for (var i = 0; i < youtube.length; i++) { // add the code here }
Next, we will retrieve the Youtube image thumbnail and display it. Youtube generates multiple image sizes, each one being accessible through the following URLs:
-
Medium Quality:
https://img.youtube.com/vi/{video-id}/mqdefault.jpg
(320×180 pixels) -
High Quality:
http://img.youtube.com/vi/G0wGs3useV8/hqdefault.jpg
(480×360 pixels) -
Standard Definition (SD):
http://img.youtube.com/vi/G0wGs3useV8/sddefault.jpg
(640×480 pixels) -
Maximum Resolution:
http://img.youtube.com/vi/G0wGs3useV8/maxresdefault.jpg
(1920×1080 pixels)
Notice that we need the corresponding Youtube video ID to append to the URL. We’ve specified the ID in data
, and we are able to retrieve it using the JavaScript .dataset
property.
// loop for (var i = 0; i < youtube.length; i++) { // thumbnail image source. var source = "https://img.youtube.com/vi/"+ youtube[i].dataset.embed +"/sddefault.jpg"; }
As you can see from the above code, we will show sdstandard.jpg
image, since most videos today come in Standard Definition (SD). Coming in at 640×480 pixels, this image thumbnail is just at the right size; not too small, nor too big. You may opt for the high-quality thumbnail image, maxresdefault.jpg
, instead, but keep in mind that Youtube video do not always come in High-definition (HD), so this particular size may not always be available.
Loading Image Thumbnail Asynchronously
Loading the image thumbnail asynchronously will allow the page to load faster. In case we have two or more embedded Youtube videos, each image thumbnail of these videos will be loaded simultaneously so they don’t prevent the page rendering flow:
// loop for (var i = 0; i < youtube.length; i++) { ... // Load the image asynchronously var image = new Image(); image.src = source; image.addEventListener( "load", function() { youtube[ i ].appendChild( image ); }( i ) ); }
This code will load the image thumbnail from the source
variable. Once it is loaded we append it to the wrapper div
:

Lastly, we add the last piece of the script.
// loop for (var i = 0; i < youtube.length; i++) { ... youtube[i].addEventListener( "click", function() { var iframe = document.createElement( "iframe" ); iframe.setAttribute( "frameborder", "0" ); iframe.setAttribute( "allowfullscreen", "" ); iframe.setAttribute( "src", "https://www.youtube.com/embed/"+ this.dataset.embed +"?rel=0&showinfo=0&autoplay=1" ); this.innerHTML = ""; this.appendChild( iframe ); } ); }
This script specifically does the following things:
- First, it attaches the
click
event to the wrapperdiv
as well as execute the anonymous function attached. - Within the function we create an
iframe
element; we create a similariframe
that the Youtube generates to embed a video, except we now insert theautoplay=1
in the URL to immediately play the video when theiframe
is set. - Lastly, it replaces the wrapper
div
content with theiframe
.
We are all set. You can give the following demo a try!
Wrapping Up
In this tutorial, we learned how to load a Youtube video upon the user’s click. This is faster and a more bandwidth-efficient way than having to pull videos directly alongside page loading, especially if you have multiple videos embedded on a single page.
And as you can see from the following screenshot, we have made a significant improvement in term of the number of HTTP requests made during the initial page load. In this case, we have trimmed it down from 22 to 5 HTTP requests.

Next
In the next tutorial, we’ll improve our code by wrapping it as a “Web Component”. Doing so will allow us to embed the Youtube video more elegantly through a custom named element. Instead of adding two div
elements as we did in this tutorial, we can simply add, for example, <youtube-embed>
.
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post