Embedding YouTube Videos Without Sucking
Published: December 2, 2013
Using YouTube to integrate video into your website is suspiciously easy. Just use YouTube's iframe embed code and voila, you now have shiny video player on your web page.
However, there's a lot of suck that comes with embedding YouTube videos that way. "How much suck?" you might ask. Well, each YouTube video you embed will force your user to download roughly 400K of data, before they even click play.
This issue has come up time and time again. There have been Stack Overflow Threads about it, blog posts, jQuery plugins, and even a WordPress plugin developed specifically to solve this problem. The purpose of this blog post is to do a quick round up of some of the solutions proposed to date, and then share some code I've developed to solve this problem.
My code focuses specifically on solving the issue in a RWD environment, something that isn't baked in to any other solutions I've seen.
How Do We Solve The Problem From A Broad Sense
The most logical solution to this problem from an abstract perspective is, rather than load the embedded video, first load a thumbnail image of the video with a play button laid over, and possibly other elements to mimic the YouTube player chrome. Then, swap in the iframe embed code only once the thumbnail has been clicked and the user has confirmed interest in watching the video.
Making this simple change cuts up to 98% percent worth of data being transferred on page load (from 400K to load the embed code to 10K to load the thumbnail)!
For Sites With Legacy Content
Skipser.com has published a blog post and some code that essentially searches the DOM for iframes with a YouTube video source and replaces them with thumbnails. A regular expression is used to extract the video id from the embed code (e.g. 'HoQN7K6HdRw' from the URL youtube.com/watch?v=HoQN7K6HdRw), and then concatenates that with YouTube thumbnail image URL string to (e.g. i.ytmig.com/vi/HoQN7K6HdRw/0.jpg) to generate the URI to the thumbnail image. An onclick attribute is added to the image, which calls a function that replaces the image with the iframe.
The beauty of this solution is that it can easily be integrated into a site that has been using the YouTube iFrame embed code from the get go. The developer or content manager will not need to make any changes other than including his gplus-youtubeembed.js script in the head of the file, and then call the optimizeYouTubeEmbed()
function in the footer after all the iframes have been added to the DOM. As Arun explains, you don’t have to worry about the iframe being downloaded because...
Javascript is synchronosly loaded by browsers. That means once your web page content is loaded by a browser, the included javascript files and inline javascript are first fetched and executed. Once all javascripts are done, the DOM is fully done and the browser loads additional content like iframes, images etc. That means if we call a javascript function right before the ending </body>
tag, it will run before the browser gets a chance to load any iframes.
A jQuery Solution
TJ Wallas published some jQuery code to GitHub in 2011 that solves the problem.
Rather than including the iframe embed code, developers use a div with class 'lite' and an 'id' equal to the YouTube video ID.
The plugin essentially searches the DOM for those divs and uses their IDs to pull the image thumbnail from the YouTube thumbnail URL string. A 'click' event handler is bound to those divs and replaces the image with the embedded video.
It is worth noting that this plugin depends on jquery.lazyload.js and doesn’t expose any configuration options to the developer. It also requires a style attribute be set with width and height equal to the dimensions of the embedded iFrame
A WordPress Plugin
Frank Gossen has developed a WordPress plugin specifically to solve this problem.
While I have not implemented it in a WordPress environment, this seems like a great solution for WordPress blogs where YouTube videos are embedded. Simply install the plugin and follow the instructions to add the link to the YouTube video and the plugin takes care of the rest. The fact that, at the time of writing this, the plugin has over 150K downloads should be a good indicator of how many people are looking to solve this problem.
Responsive Video
I will include some of my code shortly, but I want to quickly go over the topic of responsive video.
While the max-width: 100%; height: auto;
trick used for responsive images works great with HTML5 video, YouTube embeds use an iFrame, for which the trick doesn't work. Thierry Koblentz published an article titled "Creating Intrinsic Ratios for Video" to A List Apart in May of 2009 which details the commonly accepted solution to the problem.
Basically, the idea is to wrap the video in a container with padding-bottom based on the aspect ratio of the video. For example a Widescreen 16:9 video would have padding bottom of 56.25% (9 divided by 16). Similarly a 4:3 video would have padding bottom of 75%. The iframe is then placed inside with width 100% and height 100%, and perfectly fills the box.
Here’s what the CSS looks like...
Read through Theirry’s article which goes into more depth here...
http://alistapart.com/article/creating-intrinsic-ratios-for-video
jQuery.nonSuckyYouTubeEmbed.js
jQuery.nonSuckyYouTubeEmbed.js is a jQuery plugin I developed to address this issue. Similar to Wallas' solution it works by extracting the video's ID from the ID attribute of the elements it is called on. However, to increase flexibility, the plugin exposes a number of options that the implementor can customize, and is also automatically wrapped in a <div>
with all the necessary styles applied to make the videos responsive. Let's look at an example of a page that needs to embed two YouTube videos. Those videos could be represented as follows...
Then, the plugin could be called as follows...
The above code would result in two YouTube thumbnails being loaded, with a custom play button centered and laid over each, and an onclick event to swap in the YouTube iFrame.
View a demo of the plugin live in action here and browse through the source code and readme here.
An AngularJS Directive
I originally stumbled upon this issue working on an AngularJS app that was loading 10 YouTube iFrames up-front. If you happen to be working on an ng-app
with embedded YouTube videos, I really like the idea of creating a <non-sucky-youtube-embed>
directive with all this behavior encapsulated
Here’s a Gist of how you can do that...
https://gist.github.com/mpchadwick/7670014
The Ideal Solution
While all the solutions outlined above will solve this problem, just fine, in all honesty, in my mind, there's clearly a better way.
YouTube offers a number of parameters which can be set when embedding the iFrame player. For example, setting autoplay=1
will make the video automatically play on load.
In my opinion, YouTube should provide a parameter which can be set in the embed URL string to handle all this, such as preview=thumbnail
Maybe it's wishful thinking, but I think this would be a plus for all parties involved.
- Users will get a faster experience
- Developers will be happy because users are getting a better experience
- Developers will be happy to decrease bandwidth usage
- Google / YouTube decreases bandwidth transfer.
I have submitted this feature request to YouTube here...
https://code.google.com/p/gdata-issues/issues/detail?id=5591
In the meantime, use one of the solutions above so that users don't have a sucky experience on your pages that use embedded YouTube videos.