Creating Intrinsic Ratios for Video
Issue № 284

Creating Intrinsic Ratios for Video

Did you ever want to resize a video on the fly, scaling it as you would an image? Using intrinsic ratios for video, you can. This technique allows browsers to determine video dimensions based on the width of their containing block.

Article Continues Below

With intrinsic dimensions, a new width triggers a new height calculation, allowing videos to resize and giving them the ability to scale the same way images do. See example one.

The concept#section1

The idea is to create a box with the proper ratio (4:3, 16:9, etc.), then make the video inside that box stretch to fit the dimensions of the box. It’s that simple.

The trick#section2

The padding property is the magic that styles a box with an intrinsic ratio. This is because we’ll set padding in a percentage, based on the width of the containing block.

The CSS rules below illustrate how to style the parent and child to create a “magic wrapper”—a container that proportionally resizes itself depending on the width of its parent. See example two.

.wrapper-with-intrinsic-ratio {
	position: relative;
	padding-bottom: 20%;
	height: 0;
}

.element-to-stretch {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background: teal;	
}

Let’s review the declarations in each rule, starting with .wrapper-with-intrinsic-ratio.

position: relative
By declaring position: relative all child elements will position themselves in relation to this container.
padding-bottom: 20%
This declaration gives the box a specific format. Using 20% for padding makes the height of the box equal to 20% of its width.
We specifically chose to use padding-bottom rather than padding-top. This is because IE5 removes the “space” created via padding-top from the flow. In other words, using padding-top: 20% would create the layout we want, but the box would act like an absolutely positioned element, overlapping the next elements in the flow.
height: 0
Specifying a height of 0 gives this element “layout” so that IE5 and IE6 will dimension the inner box properly. To learn more, visit “On having layout.”
Note: because IE5 and IE6 treat width as a minimum width, you should not use width: 100% as a layout trigger. This causes the box to expand to fill its container rather than respect the width we set for that container.

Now, let’s consider each declaration within our .element-to-stretch rule.

position: absolute
This frees the element from the height boundary of its parent. This way, it can be positioned over the “padding area.”
top: 0
We set top: 0 to position the box near the top of its parent.
left: 0
This declaration positions the box near the left side of its parent.
width: 100%
Declaring width: 100% makes the box stretch to fill the width of its container.
height: 100%
This declaration makes the box stretch to fill the height of its container.
background: teal
We apply a color to reveal the layout of the box.

The real deal#section3

Example three uses a YouTube video (with YouTube markup), so we need to make room for the chrome. Note that the height of the chrome is static: it is 25 pixels tall, regardless of the dimensions of the video. We also change the padding value to display the video in a widescreen format (16:9).

#containingBlock {
	width: 50%;
}

.videoWrapper {
	position: relative;
	padding-bottom: 56.25%;
	padding-top: 25px;
	height: 0;
}

object,
embed {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
}

Let’s take a closer look at our new selectors and declarations, starting with the #containingBlock selector.

width: 50%
This is just a wrapper to demonstrate resizing the video based on the viewport width. In the previous example, the containing block was the body element.

Now, let’s examine a couple of the declarations under the .videoWrapper selector.

padding-bottom: 56.25%
To create a 16:9 ratio, we must divide 9 by 16 (0.5625 or 56.25%).
padding-top: 25px
To avoid issues with the broken box model (IE5 or IE6 in quirks mode), we use padding-top rather than height to create room for the chrome.

Finally, we use the object, embed selector because, while some browsers rely on object (e.g., Safari), others need embed (e.g., Firefox).

Note: I’m using YouTube’s markup for now, but at the end of this article I’ll be using valid markup and dropping embed.

The fix(es) for Internet Explorer#section4

To make this work in Internet Explorer, just add an extra wrapper. (I never said it would be pretty.) See example four.

#containingBlock {
	width: 50%;
}

.videoWrapper {
	position: relative;
	padding-top: 25px;
	padding-bottom: 56.25%;
	height: 0;
}

* html .videoWrapper {
	margin-bottom: 45px;
	margin-bot\tom: 0;
}

.videoWrapper div,
.videoWrapper embed, 
.videoWrapper object {
  position:absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
}

Let’s take a closer look at our new selectors and declarations, starting with our .videoWrapper selector.

height: 0
As seen in example two, IE5 and IE6 need “layout.”

Now, let’s look at our * html .videoWrapper selector. Called the “star html hack,” this selector makes sense only for IE6 and under, as only these versions parse the following declarations:

margin-bottom: 45px
As seen in example two, top padding creates some issue in IE5. Here, we use an arbitrary value (that should work with various chromes) to compensate for the “space” we lose by using padding-top. This is to prevent the video from overlapping subsequent elements.
margin-bottom: 0
The CSS escape notation (backslash character) within the property name acts as a filter to set a different value for IE6. IE6 “sees” this declaration, while IE5 ignores it. If you prefer using conditional comments rather than the filters above, feel free to move these declarations to IE specific style sheets or style elements in the head of the document.

Finally, the .videoWrapper div selector is the extra wrapper we need to make things work in Internet Explorer versions 5, 6, and 7.

Note: we use .videoWrapper div, .videoWrapper embed, and .videoWrapper object {} rather than .videoWrapper * {} to prevent styling alternative content.

The clean up#section5

To make this solution more versatile, we remove padding-top declarations from the previous rules and associate them with classes. This way, we can easily style videos with different ratios and/or chromes. See example five.

#containingBlock {
	width: 50%;
}

.videoWrapper {
	position: relative;
	height: 0;
}

* html .videoWrapper {
	margin-bottom: 45px;
	margin-bot\tom: 0;
}

.videoWrapper div,
.videoWrapper embed, 
.videoWrapper object {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
}

.wideScreen {
  padding-bottom: 56.25%;
}

.fourBYthree {
  padding-bottom: 75%;
}

.chrome_25 {
  padding-top: 25px;
}

.chrome_35 {
  padding-top: 35px;
}

Let’s take a look at our new classes, starting with .wideScreen.

.wideScreen
We use this class to style div.videoWrapper with a 16:9 ratio.
.fourBYthree
We use this class to style div.videoWrapper with a 4:3 ratio.
.chrome_25
This class makes room for chrome that is 25 pixels tall.
.chrome_35
This class makes room for chrome that is 35 pixels tall.

The validation issue#section6

When it comes to video, supporting web standards is not easy. First, most vendors do not encode ampersands. Most often, they rely on the twice-cooked method (using the non-standard embed element).

To make our markup standards-compliant, we first replace all ampersands in URLs with “&” Then, we implement a single-object method. Unlike the nested-objects method, this technique feeds user agents a single object, as the sample code shows below. See example six. (Line wraps marked » —Ed.)

<div id="containingBlock">
  <div class="videoWrapper">
    <div>
      <!--[if IE]>
      <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" »
width="480" height="295"> <param name="movie" value="http://www.youtube.com/v/mDRYnaajUcY »
&amp;hl=en&amp;fs=1&amp;showinfo=0" /> <![endif]--> <!--[if !IE]>--> <object type="application/x-shockwave-flash" data="http://www. »
youtube.com/v/mDRYnaajUcY&amp;hl=en&amp;fs=1&amp;showinfo=0" width="480" »
height="295"> <!--<![endif]--> <param name="quality" value="high" /> <param name="wmode" value="opaque" /> <p><a href="http://www.adobe.com/go/getflashplayer"><img alt= »
"Get Adobe Flash player" src="http://www.adobe.com/images/shared/ »
download_buttons/get_flash_player.gif"/></a></p> </object> </div> </div> ... </div>

This single-object technique facilitates generating code as the “forking” is done in a single place <object> rather than in two places <object> and </object>.

The bonus#section7

Because we have an absolutely positioned element within the box, we can hide content “behind” the video. Note: this content is outside the object. It is not “alternative content” per se. See example seven.

<div id="containingBlock">
  <div class="videoWrapper">
    <div>
      <!--[if IE]>
      <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" » 
width="480" height="295"> <param name="movie" value="http://www.youtube.com/v/ »
mDRYnaajUcY&amp;hl=en&amp;fs=1&amp;showinfo=0" /> <![endif]--> <!--[if !IE]>--> <object type="application/x-shockwave-flash" data="http://www. »
youtube.com/v/mDRYnaajUcY&amp;hl=en&amp;fs=1&amp;showinfo=0" width= »
"480" height="295"> <!--<![endif]--> <param name="quality" value="high" /> <param name="wmode" value="opaque" /> <p><a href="http://www.adobe.com/go/getflashplayer"> <img »
alt="Get Adobe Flash player" src="http://www.adobe.com/images/shared/ »
download_buttons/get_flash_player.gif"></a></p> </object> </div> <p>The following is the description of the video embeded in this
document.</p> <p>This short clip is about YouTube widescreen formatting. It
shows the two main formats (16:9, 4:3) and also explains the best way
to create a Flash movie according to the new widescreen format.</p> </div> ... </div>

The SWFObject script approach#section8

To automate this method, we can use the SWFObject script to add the .videoWrapper class we need for styling and also to plug in the wrapper we need for IE. See example eight. (Note: in this last example, the width of the containing block is set in ems.)

To add the code we need, we replace the following line in SFWObject v1.5 (around line 117):

n.innerHTML = this.getSWFHTML();

With the ones below:

n.className += " videoWrapper";
if(typeof document.documentElement.style.zoom != "undefined"){
  var wrapper4ie = document.createElement("div");
  n.appendChild(wrapper4ie);
  wrapper4ie.innerHTML = this.getSWFHTML();
}else{
  n.innerHTML = this.getSWFHTML();				
};

And that’s all there is to it. With just a little CSS and your new know-how, you too can resize and scale videos on the fly. See what you can do with the intrinsic ratio technique and share your results in the discussion.

About the Author

Thierry Koblentz

Thierry wrangles CSS and markup for Yahoo! Small Business, where his work helps countless businesses and individuals establish an online presence. A native of France, he lives in Marin County, CA, with his wife and two children, and is the owner of www.tjkdesign.com.

24 Reader Comments

  1. I like the scaling aspect of this, that will come in handy. I made a simple jQuery based 16:9 calculator based on the width of a content section:

    http://www.brianartka.com/jqueryVideoBox.html

    Its simple, but solved my issues. I did some research and there is no set “standard” to what the width of a 16:9 video should be on the net, its all over the board. The key is keeping the aspect ratio, as Thierry mentions in the article. Maybe this little tool will be helpful for others.

    Thanks!

  2. Just today, I released something *very* pertinent to this! It’s called “Video For Everybody” and it’s a block of HTML to support HTML5 <video>, fall then back to Flash and then QuickTime/WMP for other browsers. It uses a biscuit method much like you’re doing here.

    See it here: “Video For Everybody”:http://camendesign.com/code/files/video_for_everybody/test.html

    I’m wondering if I can roll your ratio work into this, to better support various Flash/QT/WMP controller sizes.

  3. Nice article. Cool way to size video and a pretty clean object tag.

    But, I can’t believe the web still doesn’t have a “real” way to embed media on a webpage.

    I truly hope the video tag is not another 5 years away from being useful on a public page. The single object method (one of the cleanest yet) and even Kroc’s project are still short of the mark. All methods still require that you know which plugin the browser should use which is madness. (Krocs method does not but instead requires at least 3 different versions of the same content which can be even worse)

    You want to serve “.3gp” video or “.ogg” audio or even mov, flv, wmv and any number of possible formats. That is: a dynamic page where the embedded media may be ANY of these formats. Today I need to create templates for each possible format and browser. Just like the bad old times. (Since the media is user generated and not of to any one particular format)

    All methods serve (at least for IE) a specific plugin. Not a file format. I have no idea which plugin is your preferred plugin to play ogg or 3gp in Firefox on Ubuntu or Opera on Windows. And frankly I’d rather not know.

    Any of you very clever people know of a way to actually render a page where the browser decides the type of plugin to be used?

  4. @MartinWestin My format only requires an MP4 and an OGG. Firefox 3.5 plays the OGG and Safari / iPhone / Flash plays the MP4. So technically, you’re only exporting one more video file, and OGG is worth using to target Firefox users (in the future) without any need for any plugins. Other browsers may adopt OGG in the future too.

    Sure the object tag is a mess, but we have to start somewhere in moving to <video> and “Video For Everybody” my first attempt at doing that.

    With a FLV file, you only get Flash and nothing else. With my method and with one MP4 file you support Safari/iPhone/Flash/QuickTime and Windows Media Player embeds. I really can’t see how that’s worse off than only Flash.

  5. This really is amazing, it’s perfect for fluid layouts that contain video… I’ve wanted to do this for ages but never worked it out, relying on JavaScript resizing instead.

    Only thing I don’t like is the horizontal scrollbar, what’s that all about?

  6. @Kroc
    Your method looks like a good one, under certain circumstances. I was not trying to pick on you but only point out that your method as well as the one in the article is still short of nirvana.

    As I understand it your method uses a fixed fallback path. Video -> quicktime -> flash -> error display, or did I get that wrong?

    What I have been looking for, and am baffled by not finding, is ONE tag (or composite mess for that matter) to embed “video”. I.E. a method that lets the browser decide the plugin to be used. The same tag should take a quicktime mov, a wmv video, or any other video format the world has ever known.

    It must be up to the browser to decide if it has support for a certain media type, not the server script, javascript or the html tags.

    The examples of formats I used are immaterial. What if I want to serve fbv files (Fabouls Basass Videoformat) or I have installed “MartinPlayer2.0”? Do you see my point?

  7. @brianartka
    With this solution there is no need to calculate height or width, the only value needed is the ratio (set via padding).

    @Kroc
    That’s an interesting approach. I think you should have no problem implementing this solution with it as long as the UA can style the element you want to stretch within the box.

    @Thomas
    The horizontal scrollbar has nothing to do with the video, it is because of the markup that is displayed within

    
    

    (it does not wrap). Use Firebug to remove this element and you should see that scrollbar disappear.

  8. @Leszek:
    Hi,
    Actually, _after_ I wrote this article (but before it was published on ALA), Ingo Chao sent me a link to the thread you mention.
    I asked the editor to somehow plug that link in the article, but that didn’t happen.
    On the other hand, our techniques are *very different* (even if both use padding) as I am relying on the width of the parent of the outer div – which allows me to use a “constant” – while you calculate the padding of the element based on its own width.
    In my opinion, that approach cannot really work as you need to keep width and padding “in sync”.

  9. Great article. I’m struggling to find a solution for the same idea, but rather than having the height of the wrapper-div based on the width of the window — I need the opposite — the width of the wrapper-div be based on the height of the window. Any thoughts on this?

  10. This is an issue I’ve been struggling with for a week – and this solves a lot of the problems I’ve been having – thanks.

    Couple of questions tho’:

    First… is it possible to add the same resizing relative to browser height?

    And second, I’m now having a problem trying to center the video in the browser window – would you have any suggestions about which method might best apply here…?

    much appreciated!

  11. @Piers

    Hi,
    As far as I know, there is no pure CSS solution to resize an element based on the height of the viewport (while keeping its aspect ratio).

    Centering the video is a matter of centering the parent container, the one that provides the padding computation.

  12. Hmm… I’m trying to use this, but something is wrong. Can you, please, take a look at following part of css:

    .videoWrapper div,
    .videoWrapper embed,
    .videoWrapper object {
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;

    and check it again? All is fine there?

    Thanks!

  13. Unfortunately, I’m don’t use video on my blog now, but I liked the article because there is a thought to use these knowledge on another project which will be a lot of video clips! Thank for article!

  14. Your article is well thought out and extremely well written. Clearly you know your CSS. But Flash is incompatible with iPhone. How do I get other video on iPhone?

  15. Very useful article even two and a half years later.

    I’m using your technique (as closely as I can) to post video on my blog. It is working for all current browsers EXCEPT IE9. I have spent hours unsuccessfully trying to figure this out. An example can be found here:

    http://blog.tlinn.com/2011/09/rogue-river/

    I don’t have any conditional statements in the <object> code; don’t know where to put them. But the video plays fine when the

    and

    are removed. Any thoughts? Thanks.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA