This article was originally written on September 2, 2010 and is now being updated to be mo’ better. It now handles YouTube videos of different aspect ratios, the new iframe embed method, and with more efficient scripts.
I expanded this idea to cover ALL video.
And now a jQuery plugin called FitVids.js that handles the vast majority of videos.
The code that YouTube gives you to embed a video is now a very simple iframe. Here’s an example:
<iframe width="1280" height="750" src="//www.youtube.com/embed/fXm9EwzSjO4?rel=0&hd=1" frameborder="0" allowfullscreen></iframe>
iFrames, including the example YouTube code above, contain external content which cannot really be measured from the parent page. The width and height settings are necessary to define the size of the iframe, as the content inside will not help shape it (like an image would). But setting a static width and height on an element poses a problem for any type of fluid/flexible design. If the parent area shrinks in width to be narrower than the video, the video will break out, not shrink to fit.
Web Designer Wall recently published an article on how to deal with fluid width video. The idea originally came from Thierry Koblentz who wrote about it on his site and A List Apart.
I love the ideas presented there. They are pure CSS (yay), clever, and do their job super well. But the solution they have for YouTube videos has two inherit shortcomings:
- The aspect ratio for the videos is pre-defined. The clever
padding-bottom: 56.25%
thing makes for an aspect ratio of 16:9 which is great for some videos but certainly not all. - You have to use additional markup. Each video needs to be wrapped in another HTML element. I wouldn’t call it non-semantic since it may make sense to use a
<figure>
or something but it’s certainly more work.
If you don’t care about either of those things, by all means use that, it’s a much cleaner solution. If that does matter, we’re going to need to employ some JavaScript.
Doing it with jQuery
The cool part about this JavaScript solution is that you just copy-and-paste YouTube embed code onto your page and don’t think about it. Whatever aspect ratio you want to set it to is fine. And no extra markup.
The basics are:
- Figure out and save the aspect ratio for all videos on the page.
- When the window is resized, figure out the new width of the content area and resize all videos to match that width with their original aspect ratio.
Here’s the full script with comments:
// By Chris Coyier & tweaked by Mathias Bynens
$(function() {
// Find all YouTube videos
var $allVideos = $("iframe[src^='http://www.youtube.com']"),
// The element that is fluid width
$fluidEl = $("body");
// Figure out and save aspect ratio for each video
$allVideos.each(function() {
$(this)
.data('aspectRatio', this.height / this.width)
// and remove the hard coded width/height
.removeAttr('height')
.removeAttr('width');
});
// When the window is resized
// (You'll probably want to debounce this)
$(window).resize(function() {
var newWidth = $fluidEl.width();
// Resize all videos according to their own aspect ratio
$allVideos.each(function() {
var $el = $(this);
$el
.width(newWidth)
.height(newWidth * $el.data('aspectRatio'));
});
// Kick off one resize to fix all videos on page load
}).resize();
});
To use this on your own site the only thing you’d need to change is the line $fluidEl = $("body");
. You’d change the selector (“body”), to whatever element on your page is the fluid width parent of the content. Perhaps that’s “#main-content” or something, if the element was <section id="main-content"></section>
.
A quick word on window.resize: Anytime you see functions running on the window resize event, you should have some alarm bells go off in your head. Browsers fire that particular event with different frequency. WebKit can fire it eleventybillion times during a quick little resizing, so if you do much heavy computational stuff you can see some adverse page performance. Here’s a plugin from Paul Irish on “debouncing” resize to deal with that problem, which I heavily recommend.
I’m going to leave the “old version” inside the download too (before this article was updated) as it handles the “old” types of YouTube embeds (object/embed elements).
YouTube access banned in our country
You should move.
Her country is obviously communist if it has a firewall, so about half the countries she could live in would make it extremely difficult for her to move
which country
turkey?
Why?
Hmm, but it works with Opera 10.61(win). Do you have the newest version?
Nice tutorial!
I checked this in Opera (latest ver. for Mac) and it works fine. It’s a little jumpy and not a smooth resize, but it works!
What a neat trick! Looks like I need to redesign my personal site to be liquid. I love how your site works when I resize the window, it’s very user friendly.
Thanks for sharing!
Unfortunately it doesn’t work when you have Flashblock on (at least in Firefox).
Still, really nice idea!
Of course it doesn’t work :P
When you have Flashblock activated it blocks the You Tube video.
..I didn’t really mean THAT
I mean when you unblock flash element, that script is not gonna work and Youtube video isn’t in fluid width because of that
One thing with window.resize is it can be fired more than you think. Some browsers fire it when you’re done with the resizing, others fire it continually as you’re resizing. I forget the particulars, but it’s mentioned in Stoyan Stefanov’s Object-Oriented JavaScript book (which is great, BTW, http://www.amazon.com/Object-Oriented-JavaScript-Stoyan-Stefanov/dp/1847194141/?tag=w3clubs-20).
Probably not a big deal, but might have some performance impacts.
You cold always throttle your function calls. This article explains a very elegant way to accomplish that.
goodness gracious its so cool. Liking the look of that cute youtube player when it is so small. :D
it works with Opera 10.61 on my Mac basically. Despite the resizing while dragging the browser window bigger or smaller.
But basically it works fine.
nice technique and tutorial btw… ;)
If I wasn’t using Youtube5 extension for Safari this would be even more awesome for me. haha, awesome stuff Chris.
wow… nice idea :)
.. have to admit – i’m too tired now to try it ;)
thank You for sharing
Thank you! I was just thinking about this the other day
Thanks, this a good think to know :)
Thanks a bunch! This is just what I need for a friend’s site.
oh Great!!! this is something very special!!!
I don’t remember doing this. I must be smarter than I (and everyone else) thought!
Very useful technique though, thanks!
Hi, the following CSS line
.img object, img embed
shouldn’t be
.img object, .img embed?
Afterall, good article.
This is a CSS solution Creating Intrinsic Ratios for Video.
The effect is cool, but I think it’d be sensible to use a noscript class on the body and set the CSS something like this:
body.noscript .img object {
width: 100%;
min-height: 350px;
}
That way, the aspect ratio doesn’t change – but at least the width does, instead of being fixed without JS.
Ethan Marcotte has a a script for dealing with videos:
http://unstoppablerobotninja.com/entry/fluid-images
That’s excatly what I am searching for, but …
I’m a young developper and I don’t know where to put those scripts !
Helllllllpppppppp :-)
Dude, this is great! I’m glad you figured out how to do it =D
This is awesome! Will definitely use it.
Also, the rounded corners also work in Safari, not just Chrome.
Something along the same lines occurred to me with an image slideshow. The client requested it made so that the slideshow resizes depending on the screen resolution.
Since the slideshow is fairly basic (just puts an image on top of the other and then fades) I thought it would be easy to do, as it turns out it wasn’t. The solution I found was to make it so that all the images (position: absolute) were contained into a div (position: relative), and then set the images to clip to the divs borders (top:0;right:0;bottom:0;left:0) and have the same width as the div (width:100%). It didn’t quite work until I used one of the images to size the div to begin with (position:relative).
Could this be done as well to make the object and/or embed tags resize fluidly?
Really nice technique, found the rounded corners worked in Safari also. LT
HELP!
Hmmm… excellent but doesn’t seem to work when using videos of different aspect ratios (4:3 and 16:9)…
seems like once the script gets it’s first set of width and height data, it applies that to every YouTube player on the page, regardless of the other players’ width/height. How could you modify the script to re-check every player on the page?
:)
I see what you mean Sam. That is indeed how the script works is it looks at the ratio of the first video and treats them all like that. I’ll make a note to try and update this to accommodate videos of different ratios on the same page.
This article is now updated to deal with that.
good
like this
I think Paul’s comment about a pure css solution would be best, but I think the script can be even more efficient by only dealing with the height.
Does it work with Youtube videos only, or with other embeddable videos (e.g. Vimeo, dailymotion, etc… ) too?
Thanks for your script.
What i did: Giving the iframe the correct size ( instead of height:750 give it
height:720 ) and at the end of your script append “+30” to the line:
.height(newWidth * $el.data(‘aspectRatio’) +30);
So the navigation bar ( has always a static height) isn’t included in the aspectRation and you should get no more black bars in the video container when resizing.
Dont ya just love Jquery, Fab idea using an iframe.
Is YouTube the only video source I can use?
nice info. i cheked it with firefox 3 it worked . will give a try with version 4. hope it goes well .
Am I missing something here? Im sure you can have fluid width video’s without the need for JavaScript, Ive done it myself on a number of sites…
Take this demo page for example.
http://webdesignerwall.com/demo/elastic-videos/
Hate to be a nag but I feel like if you read the article it covers that.
A side note….If you’re using a element, I think you can use max-width:100%; and it’ll flex to fit whatever parent it’s in (like an image). Won’t work in IE6, however.
So elegant – loving the simplicity. Bookmarked!
Everyone watching in fullscreen anyway.
Another cool thing this allows you to do is wrap the iframe in a surrounding element, set the iframe width/height to 100%, set overflow: auto and resize: both for the surrounding element. Pretty cool!
yeah i love this. it is cool to host your own videos like chris does, but it’s so easy to just let youtube do the heavy work, and i am obsessed with fluid width ever since i started learning css.
You own too many Apple products ;) Iframes are not iFrames!
Thanks! Works well with vimeo too. How would you target more than one type?
say vimeo and youtube?
Well, I came across this code today but also noticed that the youtube iframe embed codes have changed the src attribute (at least for me here).
I know I know, this thread is really old – but here is my small contribution anyway in case anyone else stumbles upon it.
Change
To
This is great and exactly what i’m looking for. I’m still a bit of a novice, can anyone clarify how you use this with WordPress. Does the script go in the page template files or can you add it using the page/post text editor?
I wrote a WordPress plugin that adds FitVids.js for you. FitVids.js doesn’t load by default, but if you install the plugin then you can enable Fitvids.js from its settings page.
It’s called Video Embeds.
Hi. I wonder if it’s possible to have two columns – with different widths and to resize videoes for both columns accordingly?
So genius! Thank you so much! Absolutely love CSS-Tricks.