|
@ -0,0 +1,186 @@ |
|
|
|
|
|
# Background |
|
|
|
|
|
|
|
|
|
|
|
The concept of lazy loading is a design pattern where you only download the required scripts/content when the client needs it rather than when the page is loaded. |
|
|
|
|
|
The most iconic example is the "infinite" feed that social media sites like Instagram use. |
|
|
|
|
|
Rather than dump a ton of content to the client at once, Instagram dynamically loads more content once you reach the end of the page. |
|
|
|
|
|
This allows websites to save bandwidth by only sending the client what they need when they need it. |
|
|
|
|
|
|
|
|
|
|
|
When a youtube video is embedded into a website, it pulls a ton of scripts which are required to play the video. |
|
|
|
|
|
However, when you embed a youtube video on a blog post, most people are not going to watch that video. |
|
|
|
|
|
Even if the visitor wanted to watch that video, there is no reason why all the scripts should be loaded when you initially land on the page. |
|
|
|
|
|
Rather than embed the video normally, you can instead simply have a the thumbnail of the video with a play button on it. |
|
|
|
|
|
When the client clicks the play button, the youtube scripts are then loaded. |
|
|
|
|
|
|
|
|
|
|
|
# Performance Without Lazy Loading |
|
|
|
|
|
|
|
|
|
|
|
![Before Performance Score](media/youtubeLazyLoading/beforeTable.png) |
|
|
|
|
|
|
|
|
|
|
|
![Before Table Analysis of embedded youtube videos](media/youtubeLazyLoading/before3.png) |
|
|
|
|
|
|
|
|
|
|
|
A very basic blog post with two Youtube videos is **1.5 MB** in size. |
|
|
|
|
|
That is a rather large page for a client to download and render. |
|
|
|
|
|
Notice that 65% of the content by size is from Youtube and 29 requests were from Google domains. |
|
|
|
|
|
|
|
|
|
|
|
# Performance with Lazy Loading |
|
|
|
|
|
|
|
|
|
|
|
![After Performance Score](media/youtubeLazyLoading/afterTable.png) |
|
|
|
|
|
|
|
|
|
|
|
![After Table Analysis of embedded youtube videos](media/youtubeLazyLoading/after2.png) |
|
|
|
|
|
|
|
|
|
|
|
After lazy loading Youtube videos I was able to reduce the size of this blog post by nearly 1 MB. |
|
|
|
|
|
This also decreased the page load time by 75%. |
|
|
|
|
|
Additional tests show's that each embedded youtube video consumes around 500 KB. |
|
|
|
|
|
Using the lazy loading method you can slash that 500 KB to a mere 100 KB-- size of just the thumbnail. |
|
|
|
|
|
|
|
|
|
|
|
# Code Used |
|
|
|
|
|
|
|
|
|
|
|
## Javascript |
|
|
|
|
|
|
|
|
|
|
|
This is some basic JavaScript code which selects all of the "youtube" embedded videos on our page and adds a play button handler. |
|
|
|
|
|
When the button is clicked, it updates the div to have an Iframe with the appropriate embedded youtube video. |
|
|
|
|
|
If you are already using jQuery, you could use that but, I did not since the **goal** of this is to optimize the page load time. |
|
|
|
|
|
The [jQuery library](https://mathiasbynens.be/demo/jquery-size) is nearly 50 KB. |
|
|
|
|
|
|
|
|
|
|
|
```javascript |
|
|
|
|
|
<script> |
|
|
|
|
|
( function() { |
|
|
|
|
|
|
|
|
|
|
|
var youtube = document.querySelectorAll( ".youtube" ); |
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < youtube.length; i++) { |
|
|
|
|
|
|
|
|
|
|
|
var source = "https://img.youtube.com/vi/"+ youtube[i].dataset.embed +"/sddefault.jpg"; |
|
|
|
|
|
|
|
|
|
|
|
var image = new Image(); |
|
|
|
|
|
image.src = source; |
|
|
|
|
|
image.addEventListener( "load", function() { |
|
|
|
|
|
youtube[ i ].appendChild( image ); |
|
|
|
|
|
}( 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 ); |
|
|
|
|
|
} ); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
} )(); |
|
|
|
|
|
</script> |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
## CSS |
|
|
|
|
|
|
|
|
|
|
|
This CSS defines how the embedded youtube video looks before you click the play button. |
|
|
|
|
|
|
|
|
|
|
|
```CSS |
|
|
|
|
|
.wrapper { |
|
|
|
|
|
max-width: 680px; |
|
|
|
|
|
margin: 60px auto; |
|
|
|
|
|
padding: 0 20px; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.youtube { |
|
|
|
|
|
background-color: #000; |
|
|
|
|
|
margin-bottom: 30px; |
|
|
|
|
|
position: relative; |
|
|
|
|
|
padding-top: 56.25%; |
|
|
|
|
|
overflow: hidden; |
|
|
|
|
|
cursor: pointer; |
|
|
|
|
|
} |
|
|
|
|
|
.youtube img { |
|
|
|
|
|
width: 100%; |
|
|
|
|
|
top: -16.82%; |
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
### Example |
|
|
|
|
|
|
|
|
|
|
|
<youtube src="DoDaHmyIPvQ" /> |
|
|
|
|
|
|
|
|
|
|
|
## HTML |
|
|
|
|
|
|
|
|
|
|
|
Rather than use the embed code that youtube provides, you have to use the following code to integrate with the CSS and JS written. |
|
|
|
|
|
All you need from the youtube video is the ID which appears in the link associated with that video. |
|
|
|
|
|
|
|
|
|
|
|
```HTML |
|
|
|
|
|
<div class="wrapper"> |
|
|
|
|
|
<div class="youtube" data-embed="DoDaHmyIPvQ"> |
|
|
|
|
|
<div class="play-button"></div> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
## Node Templating Stuff |
|
|
|
|
|
|
|
|
|
|
|
When witting blog posts in Markdown, it is not convenient to include 5 lines of HTML to embed a video. |
|
|
|
|
|
On my node server I wrote some code to convert a simpler "youtube tag" into the 5 lines of HTML shown above. |
|
|
|
|
|
This is completely optional. |
|
|
|
|
|
|
|
|
|
|
|
```javascript |
|
|
|
|
|
//regular expression to detect custom youtube video tag |
|
|
|
|
|
//<youtube src="" /> |
|
|
|
|
|
var re = /\<youtube .*?>/; |
|
|
|
|
|
|
|
|
|
|
|
//result is a string which contains a HTML document |
|
|
|
|
|
|
|
|
|
|
|
while (result.search(re) != -1) |
|
|
|
|
|
{ |
|
|
|
|
|
var ytid = result.substring(result.search(re) + 14, result.search(re)+ 11 + 14); |
|
|
|
|
|
var youtubeHTML = "<div class=\"wrapper\">\n" + |
|
|
|
|
|
"\t<div class=\"youtube\" data-embed=\"" + |
|
|
|
|
|
ytid + |
|
|
|
|
|
"\" />\n" + |
|
|
|
|
|
"\t\t<div class=\"play-button\"></div>\n" + |
|
|
|
|
|
"\t</div>\n" + |
|
|
|
|
|
"</div>\n"; |
|
|
|
|
|
|
|
|
|
|
|
var original = "<youtube src=\"" + ytid + "\" />"; |
|
|
|
|
|
|
|
|
|
|
|
result = result.split(original).join(youtubeHTML); |
|
|
|
|
|
} |
|
|
|
|
|
``` |