Yesterday I had to embed some YouTube videos in one of the articles I was
writing about Raspberry Pi’s,
and since I usually do not embed videos that often and rarely
multiple of them, I never really upset about the performances penalty for one iframe,
but after I added multiple of them I saw a massive web page loading degradation.
So it occurred to me how could I embed YouTube videos more efficiently. The first
idea that came into my mind was lazy-loading, but that would require JavaScript
and listen for scrolling events, so that idea turned me off immediately.
The next idea was how about just showing a link to the YouTube page with
a video thumbnail inside. Now that looked more efficient to me.
So I started Duck Ducking the web for YouTube thumbnails API if there
was any publicly available without registering for the dev program and all those
hassles. To my surprise I found the answer immediately on the stack overflow
question How do I get a YouTube video thumbnail from the YouTube
API?.
Apparently, you can get a thumbnail image for any YouTube video from one of their subdomains like
https://img.youtube.com or https://i.ytimg.com. Now, this probably isn’t the best way, since at any moment
Google could change or limit access to these domains. So a more secure and proper way would be signing up for the Data API and have peace of mind, but that I wanted a quick solution so I accepted the risk for the moment.
Back to the YouTube video images! This answer on Stack Overflow has put a nice table on
all sizes of images you can access:
Width | Height | URL
------|--------|----
120 | 90 | //i.ytimg.com/vi/<VIDEO ID>/1.jpg
120 | 90 | //i.ytimg.com/vi/<VIDEO ID>/2.jpg
120 | 90 | //i.ytimg.com/vi/<VIDEO ID>/3.jpg
120 | 90 | //i.ytimg.com/vi/<VIDEO ID>/default.jpg
320 | 180 | //i.ytimg.com/vi/<VIDEO ID>/mq1.jpg
320 | 180 | //i.ytimg.com/vi/<VIDEO ID>/mq2.jpg
320 | 180 | //i.ytimg.com/vi/<VIDEO ID>/mq3.jpg
320 | 180 | //i.ytimg.com/vi/<VIDEO ID>/mqdefault.jpg
480 | 360 | //i.ytimg.com/vi/<VIDEO ID>/0.jpg
480 | 360 | //i.ytimg.com/vi/<VIDEO ID>/hq1.jpg
480 | 360 | //i.ytimg.com/vi/<VIDEO ID>/hq2.jpg
480 | 360 | //i.ytimg.com/vi/<VIDEO ID>/hq3.jpg
480 | 360 | //i.ytimg.com/vi/<VIDEO ID>/hqdefault.jpg
640 | 480 | //i.ytimg.com/vi/<VIDEO ID>/sd1.jpg
640 | 480 | //i.ytimg.com/vi/<VIDEO ID>/sd2.jpg
640 | 480 | //i.ytimg.com/vi/<VIDEO ID>/sd3.jpg
640 | 480 | //i.ytimg.com/vi/<VIDEO ID>/sddefault.jpg
1280 | 720 | //i.ytimg.com/vi/<VIDEO ID>/hq720.jpg
1920 | 1080 | //i.ytimg.com/vi/<VIDEO ID>/maxresdefault.jpg
And in addition, all these images are also provided in WebP image format which
is nice, the problem is it’s not available for images so it’s better to stick with jpg format.
HTML markup
Now that I can access the video thumbnails, I did quick markup of how the code
would look like:
<div class="youtube">
<a href="https://www.youtube.com/watch?v=VIDEO_ID" target="_blank">
<figure>
<img src="https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg" alt="VIDEO_TITLE" />
<figcaption>VIDEO_TITLE</figcaption>
</figure>
</a>
</div>
But considering the different image sizes, we could easily make a responsive
markup using the srcset property.
<div class="youtube">
<a href="https://www.youtube.com/watch?v=VIDEO_ID" target="_blank">
<figure>
<img src="https://img.youtube.com/vi/VIDEO_ID/default.jpg"
srcset="https://img.youtube.com/vi/VIDEO_ID/mqdefault.jpg 320w,
https://img.youtube.com/vi/VIDEO_ID/hqdefault.jpg 480w,
https://img.youtube.com/vi/VIDEO_ID/sddefault.jpg 640w,
https://img.youtube.com/vi/VIDEO_ID/hq720.jpg 1280w,
https://img.youtube.com/vi/VIDEO_ID/maxresdefault.jpg 1920w"
alt="VIDEO_TITLE" />
<figcaption>VIDEO_TITLE</figcaption>
</figure>
</a>
</div>
CSS styling
My goal was to make it look as much as possible as the YouTube iframe without
complicating the HTML markup too much. I managed to do that with some use of CSS
pseudo-elements, for example, to add the shadow under the title of the video and make it more readable, and place the YouTube SVG icon from the beautiful Feather Icons as the play button.
.youtube {
position: relative;
a {
text-decoration: none;
&:before {
content: '';
width: 100%;
height: 20%;
position: absolute;
top: 0;
background-image: linear-gradient(#000, transparent);
}
&:after {
content: "";
background: url(https://cdn.jsdelivr.net/npm/[email protected]/dist/icons/youtube.svg)
no-repeat;
background-position: center;
background-size: 100px 100px;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
}
img {
width: 100%;
height: auto;
}
figure {
margin: 0;
}
figcaption {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
color: white;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
}
The result
The result is very pleasing aesthetically and offering some big performance improvements at the same time, the only trade-off to this approach is that the visitors
will not be able the play the video directly from the page but they will be redirected to the YouTube page, and I can live with that.
Take a look at the demo on Codepen, or visit this page on Dev & Gear to see it in production.
See the Pen An alternative way of embedding YouTube videos without impacting web perf by Bojan Vidanovic (@bojanvidanovic)
on CodePen.
Conlusion
This technique at the end is a very simple one, and it can be easily implemented in any framework as a reusable component. I implemented it in Hugo as a shortcode for example. Anyway, I believe that every code has some room for improvement just like this one, so if you think this can be done better let me know in the comments.