64

I want to scale an iFrame through CSS to width: 100%, and the height should scale proportionally to the width.

With an <img> tag this works fine.

Both the image and the iFrame have defined width and height in the html.

Here some examples:

<html>
    <style>
        #a{ width: 500px; }
        img{ width: 100%; height: auto }
    </style>
    <body>
        <div id="a">
            <img src="http://lorempixel.com/200/150/" width="200" height="150" />
        </div>
    </body>

This works great on images, but I would like the same behaviour for iFrames:

<html>
    <style>
        #a{ width: 900px; background: grey;}
        iframe{ width: 100%; height: auto }
    </style>
    <body>
        <div id="a">
            <iframe width="560" height="315" src="http://www.youtube.com/embed/RksyMaJiD8Y" frameborder="0" allowfullscreen></iframe>
        </div>
    </body>

The iFrame renders 100% wide but does not scale it's height proportional like the image does.

admdrew
  • 3,790
  • 4
  • 27
  • 39
Oliver
  • 855
  • 1
  • 7
  • 10

6 Answers6

116

Big difference between an image and an iframe is the fact that an image keeps its aspect-ratio. You could combine an image and an iframe with will result in a responsive iframe. Hope this answerers your question.

Check this link for example : http://jsfiddle.net/Masau/7WRHM/

HTML:

<div class="wrapper">
    <div class="h_iframe">
        <!-- a transparent image is preferable -->
        <img class="ratio" src="http://placehold.it/16x9"/>
        <iframe src="http://www.youtube.com/embed/WsFWhL4Y84Y" frameborder="0" allowfullscreen></iframe>
    </div>
    <p>Please scale the "result" window to notice the effect.</p>
</div>

CSS:

html,body        {height:100%;}
.wrapper         {width:80%;height:100%;margin:0 auto;background:#CCC}
.h_iframe        {position:relative;}
.h_iframe .ratio {display:block;width:100%;height:auto;}
.h_iframe iframe {position:absolute;top:0;left:0;width:100%; height:100%;}

note: This only works with a fixed aspect-ratio.

Pascal
  • 16,846
  • 4
  • 60
  • 69
Rik
  • 1,313
  • 1
  • 8
  • 4
69

I suppose this is a cleaner approach. It works with inline height and width properties (I set random value in the fiddle to prove that) and with CSS max-width property.

HTML:

<div class="wrapper">
    <div class="h_iframe">
        <iframe height="2" width="2" src="http://www.youtube.com/embed/WsFWhL4Y84Y" frameborder="0" allowfullscreen></iframe>
    </div>
    <p>Please scale the "result" window to notice the effect.</p>
</div>

CSS:

html,body        {height: 100%;}
.wrapper         {width: 80%; max-width: 600px; height: 100%; margin: 0 auto; background: #CCC}
.h_iframe        {position: relative; padding-top: 56%;}
.h_iframe iframe {position: absolute; top: 0; left: 0; width: 100%; height: 100%;}

http://jsfiddle.net/7WRHM/1001/

Dharman
  • 30,962
  • 25
  • 85
  • 135
Simone Lazzari
  • 728
  • 5
  • 9
  • 11
    I wanted to add some more visibility to this answer, as it seems like a clear winner. The previous answer involving adding a hidden img to trigger scaling is clever, but forcing an additional http request, specifically on mobile, is far from ideal. This pure CSS answer is a much better approach. – briznad Apr 29 '14 at 15:10
  • 1
    padding-top should be 56.25% or the video is wider than 16/9 – Ivan Nikitin Oct 14 '14 at 15:56
  • 2
    @Simone, off-topic but yes I personally prefer the css only approach. A good read is : http://alistapart.com/article/creating-intrinsic-ratios-for-video For IE7 support check http://alistapart.com/d/creating-intrinsic-ratios-for-video/example4.html – Rik Jan 14 '15 at 12:27
30

I like this solution best. Simple, scalable, responsive. The idea here is to create a zero-height outer div with bottom padding set to the aspect ratio of the video. The iframe is scaled to 100% in both width and height, completely filling the outer container. The outer container automatically adjusts its height according to its width, and the iframe inside adjusts itself accordingly.

<div style="position:relative; width:100%; height:0px; padding-bottom:56.25%;">
    <iframe style="position:absolute; left:0; top:0; width:100%; height:100%"
        src="http://www.youtube.com/embed/RksyMaJiD8Y">
    </iframe>
</div>

The only variable here is the padding-bottom value in the outer div. It's 75% for 4:3 aspect ratio videos, and 56.25% for widescreen 16:9 aspect ratio videos.

Anachronist
  • 1,032
  • 12
  • 16
  • This breaks if the div's parent is not exactly the same width. – Walf Jun 30 '23 at 03:44
  • @Walf - how? The widths are all 100% relative to the parent. – Anachronist Jul 01 '23 at 04:05
  • Because these sizing wrappers are typically placed adjacent to other content elements in the DOM which rely on padding to size them appropriately. As a result, doing only a single wrapper to fix the aspect ratio makes it more fragile, and that embed can either appear wider than the other content, or overflow, or both: https://jsfiddle.net/bjvLzkq7/ It's a really common issue which you've likely seen yourself on a mobile device, on sites that embed YouTube videos. Often the aspect is okay, but the video spills over the right edge same distance as the other content's padding. – Walf Jul 03 '23 at 04:42
9

You could use viewport units here instead of %. Like this:

iframe {
    max-width: 100vw;
    max-height: 56.25vw; /* height/width ratio = 315/560 = .5625 */
}

DEMO (Resize to see the effect)

body {
  margin: 0;
}
.a {
  max-width: 560px;
  background: grey;
}
img {
  width: 100%;
  height: auto
}
iframe {
  max-width: 100vw;
  max-height: 56.25vw;
  /* 315/560 = .5625 */
}
<div class="a">
  <img src="http://lorempixel.com/560/315/" width="560" height="315" />
</div>

<div class="a">
  <iframe width="560" height="315" src="http://www.youtube.com/embed/RksyMaJiD8Y" frameborder="0" allowfullscreen></iframe>
</div>
Danield
  • 121,619
  • 37
  • 226
  • 255
  • Hello, I think vw are not suited for this. http://jsfiddle.net/bancaf/615y5aou/ here, in a semplified example based on your code, the iframe height stays locked to a default 150px (browser default min height for an iframe I think). What am I missing? – DrLightman Nov 10 '15 at 14:32
  • 2
    This solution is fantastic because it doesn't require the HTML to have any extra tags and there's no JavaScript involved. – Neil C. Obremski Jun 02 '16 at 20:42
3

@Anachronist is closest here, @Simone not far off. The caveat with percentage padding on an element is that it's based on its parent's width, not its own. If the width is different to your container (and often is), the aspect will be wrong.

The most bulletproof answer is to use two wrapping divs:

body {
  /* for this demo */
  background: lightgray;
}
.fixed-aspect-wrapper {
  /* can accept any padding to match its siblings in the DOM */
  padding: 0;
  /* width can be anything or nothing, it doesn't matter */
  width: 60%;
  max-width: 800px;
}
.fixed-aspect-padder {
  /* this stretches the height of first wrapper but maintains a natural width at the correct ratio */
  height: 0;
  margin: 0;
  width: auto;
  position: relative;
  /* last padding dimension is (100 * height / width) of item to be scaled,
     here is the common 16:9 ratio */
  padding: 0 0 56.25%;
}
.whatever-needs-the-fixed-aspect {
  /* this fills the available space */
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 0;
  /* for this demo */
  background: white;
}
<div class="fixed-aspect-wrapper">
  <div class="fixed-aspect-padder">
    <iframe class="whatever-needs-the-fixed-aspect" src="/"></iframe>
  </div>
</div>
Walf
  • 8,535
  • 2
  • 44
  • 59
2

None of these solutions worked for me inside a Weebly "add your own html" box. Not sure what they are doing with their code. But I found this solution at https://benmarshall.me/responsive-iframes/ and it works perfectly.

CSS

.iframe-container {
  overflow: hidden;
  padding-top: 56.25%;
  position: relative;
}

.iframe-container iframe {
   border: 0;
   height: 100%;
   left: 0;
   position: absolute;
   top: 0;
   width: 100%;
}

/* 4x3 Aspect Ratio */
.iframe-container-4x3 {
  padding-top: 75%;
}

HTML

<div class="iframe-container">
  <iframe src="https://player.vimeo.com/video/106466360" allowfullscreen></iframe>
</div>
  • Not only did this work for me...but I was also able to add one more additional wrapper div around it so I could replace an in a standard Angular Material Mat-Card and it filled up the entire space like the without having to dink around with their standard settings! Thanks! .MatCardVid { position: relative; left: -16px; width: calc(100% + 32px); margin-bottom: 20px; // background-color: lightcyan; } – AppDreamer Sep 22 '20 at 14:36
  • This is functionally the same as the current top answer, and like that one, this also breaks if the element containing the `.iframe-container' is wider than it. – Walf Jun 30 '23 at 05:56