Make your embedded videos responsive with CSS or JS
When you insert an embedded video from Youtube, Vimeo, Dailymotion or any other video site, you’re asked to insert a certain HTML code inside your website (a DIV container) but the problem comes when your container for the video doesn’t have a fixed constant width; with the importance that responsive web design has drastically gained over the past years, it’s imperative that you adapt the videos you insert on your site, blog or app to the container size (width) because most of the times, these embedded objects, whether it’s an IFRAME (YouTube does this), an HTML5
video tag or an
object one, they often come with fixed values (as HTML attributes) for the height and the width of said video.
The strategies that have been arising lately have been a few but the most notorious ones are:
An old trick mentioned in [this article] by CSSTricks and discovered in 2009 that consists of wrapping Iframes in a container that was positioned as “absolute”, relative to an outer wrapper div that relied on a percentage based
padding-bottomvalue for the height. This trick then came to become a famous jQuery plugin called Fitvids.js (made by Chris Coyer of CSSTricks).
Grabbing every Iframe (only those with a video embed) and object HTML tag and determining its aspect ratio (it’s often preferred to use the 16:9 widescreen ratio), then making the width equal to its container’s width and then setting the height equal to a new height which is calculated with the aspect ratio. But what if the user resizes the page? We can create a “window resize” event listener that triggers a function when the viewport size changes; after that, all we have to do is encapsulate the resizing algorithm inside a throttled function (to lessen the operations per second of the event listener triggered function) and adding it to the event listener.
If you wonder why I only mentioned Iframes but not HTML5 video tags was because HTML5 video tags happen to be able to have a
width: 100% !importantCSS property.
This is what CSSTrick proposes for Iframes:
embed tags, you can modify the second CSS block to look like this:
This way you will force those three HTML tags to take all the size of the video wrapper box (hence the
100% size values). Now, to make use of this class all you need to do is insert an embedded video code inside a div with the class of
Someone on Reddit also said that Bootstrap has a helper class for this, you may want to check that out.
We’re going to start by adding very important polyfills. In layman’s terms, this piece of code will support certain browsers for certain features that they may not have available.
But wait, there’s more! replacing jQuery comes with some pros and cons, and one of the cons is having to add this monstrous polyfill that I took from StackOverflow just to support the
DOMContentLoaded (equivalent to
$(document).ready) in order to let the document be parsed first before executing the JS code; you can opt out from pasting this one in your code if you’d like to tell IE6, IE7 and IE8 to f*ck off:
body HTML tag.
You may be tempted to use
Below the polyfill we just added, insert the following functions:
I won’t explain much of what this code does because you may have already used those functions but to summarize it all,
_each will iterate over an array (in this case, an array of DOM elements) and
_filter takes an array and returns a new one filled with elements from the original array that pass a certain test or condition.
This algorithm is kinda simple, to be honest, all it does is resize the DOM element corresponding to the video object to be resized by using the container element’s width and an aspect ratio that can be either pre-defined as a constant or obtained dynamically using the video’s width and height HTML properties. I chose to use a pre-defined aspect ratio, the 16:9 ratio is my favorite but you can choose to do what you think is correct. Add the following function below the array iterative method functions:
Very simple, huh? All this does is change the width of the video to the current width of the containing DOM element and the height of the video to the width multiplied by the aspect ratio’s factor.
In the following section, we’re going to create a function that resizes every video on the page, but as it’s explained in that section, you should probably prevent it from executing very quickly; remember that the resize event might trigger the callback function in small intervals because even if one single pixel changes, it will trigger the callback.
We need to add a debouncer, which will create a new function based on one that’s been passed to it and will make sure it doesn’t execute again until a certain amount of time has passed (in milliseconds); I’ve taken the liberty of using David Walsh’s debounce snippet:
If the debounce function doesn’t work in IE6 up to IE8, find another alternative or remove the arguments object and its implementation inside this snippet since we’re not going to need arguments for this function.
ready method) so we can start selecting some DOM elements. It’s time to start by adding an event listener for the parsed document and inside, grab every Iframe that is an embedded video (you can also add object tags, it’s up to you).
We start by selecting our Iframes and initialize a regular expression to detect YouTube or Vimeo videos (add more if you want or need) and then, the
videos variable will be an array of Iframes that include the word “youtube” or “vimeo” in the
src attribute. The reason I included a function inside the
docReady callback was because I wanted it to have access to the
videos variable and possibly, if you wanted a certain element’s width as the containing element instead of the parent element of the video, you can set up a variable that selects the DOM element and then I use its offsetWidth instead of
video.parentElement.offsetWidth. If you don’t know what I mean, take this blog again as an example, since I will only add videos to the
.post div (only the first one it finds) and not somewhere else, I can replace the value of
Note: the document.getElementsByClassName method needs a polyfill if you’re adding support for older browsers or versions of IE. The polyfill can be found at Mozilla Developer Network (I think) or this Gist will all credit due to the author Eike Send.
The function that gets declared inside the scope of the callback (docReady) iterates over the
videos variable and resizes each of those videos. You can play around with scope and context but this is the way I chose to do it; doesn’t mean you can’t modify it. Actually… it’s not a bad idea to take the
resizeVideos function outside and place the three first statements inside that function at its top for it to have access to said DOM elements.
After that, we call that very function and add an event listener so that when the viewport’s width changes, the function
resizeVideos gets called, but, notice the
_debounce wrapper? It’s returning a function that can only be called once 70 milliseconds have passed since the last execution; this is useful because a resize event is very CPU intensive and throttling it will prevent it from executing every time a single pixel changes during the window resizing event.
If you are sick of polyfills and long blocks of code, you can use this jQuery version that I prepared. It’s the same code but shorter because of the obvious reasons; it’s also compatible with all browsers that jQuery supports and can be exported into its own micro-plugin:
If you are looking for the debounce function, go upside a bit and you’ll find it.