Make Iframe to fit 100% of container's remaining height

HtmlCssIframe

Html Problem Overview


I want to design a web page with a banner and an iframe. I hope the iframe can fill all the remaining page height and be resized automatically as the browser is resizing. Is it possible to get it done without writing JavaScript code, only with CSS?

I tried to set height:100% on iframe, the result is quite close but the iframe tried to fill the whole page height, including the 30px height of banner div element, so I got unnecessary vertical scrollbar. It's not perfect.

I tried CSS margin, padding attribute on DIV to occupy the whole remaining height of a web page successfully, but the trick didn't work on iframe.

 <body>
    <div style="width:100%; height:30px; background-color:#cccccc;">Banner</div>
    <iframe src="http: //www.google.com.tw" style="width:100%; height:100%;"></iframe>
</body>

Html Solutions


Solution 1 - Html

Update in 2019

TL;DR: Today the best option is - flexbox. Everything supports it nicely and has for years. Go for that and don't look back. Here is a code sample for flexbox:

body, html {width: 100%; height: 100%; margin: 0; padding: 0}
.row-container {display: flex; width: 100%; height: 100%; flex-direction: column; background-color: blue; overflow: hidden;}
.first-row {background-color: lime; }
.second-row { flex-grow: 1; border: none; margin: 0; padding: 0; }

<div class="row-container">
  <div class="first-row">
    <p>Some text</p>
    <p>And some more text</p>
  </div>
  <iframe src="https://jsfiddle.net/about" class="second-row"></iframe>
</div>

The rest of this answer is left for learning & historical reasons.

The trick is to understand what the 100% is taken of. Reading CSS specs can help you there.

To make a long story short - there is such a thing as "containing block" - which is not necessary the parent element. Simply said, it is the first element up the hierarchy that has position:relative or position:absolute. Or the body element itself if there is nothing else. So, when you say "width: 100%", it checks the width of the "containing block" and sets the width of your element to the same size. If there was something else there, then you might get contents of a "containing block" that are larger than itself (thus "overflowing").

Height works the same way. With one exception. You can't get height to 100% of the browser window. The very top level element, against which 100% can be calculated, is the body (or html? not sure) element, and that stretches just enough to contain its contents. Specifying height:100% on it will have no effect, because it has no "parent element" against which to measure 100%. Window itself doesn't count. ;)

To make something stretch exactly 100% of the window, you have two choices:

  1. Use JavaScript
  2. Don't use DOCTYPE. This is not a good practice, but it puts the browsers in "quirks mode", in which you can do height="100%" on elements and it will stretch them to the window size. Do note, that the rest of your page will probably have to be changed too to accommodate for the DOCTYPE changes.

Update: I'm not sure if I wasn't wrong already when I posted this, but this certainly is outdated now. Today you can do this in your stylesheet: html, body { height: 100% } and it will actually stretch to the whole of your viewport. Even with a DOCTYPE. min-height: 100% could also be useful, depending on your situation.

And I wouldn't advise anyone to make a quirks-mode document anymore either, because it causes way more headaches than solves them. Every browser has a different quirks-mode, so getting your page to look consistently across browsers becomes two orders of magnitude more difficult. Use a DOCTYPE. Always. Preferably the HTML5 one - <!DOCTYPE html>. It's easy to remember and works like a charm in all browsers, even the 10 years old ones.

The only exception is when you have to support something like IE5 or something. If you're there, then you're on your own anyway. Those ancient browsers are nothing like the browsers today, and little advice that is given here will help you with them. On the bright side, if you're there, you probably just have to support ONE kind of browser, which gets rid of the compatibility problems.

Good luck!

Update 2: Hey, it's been a long time! 6 years later, new options are on the scene. I just had a discussion in the comments below, here are more tricks for you that work in today's browsers.

Option 1 - absolute positioning. Nice and clean for when you know the precise height of the first part.

body, html {width: 100%; height: 100%; margin: 0; padding: 0}
.first-row {position: absolute;top: 0; left: 0; right: 0; height: 100px; background-color: lime;}
.second-row {position: absolute; top: 100px; left: 0; right: 0; bottom: 0; background-color: red }
.second-row iframe {display: block; width: 100%; height: 100%; border: none;}

<div class="first-row">
  <p>Some text</p>
  <p>And some more text</p>
</div>
<div class="second-row">
  <iframe src="https://jsfiddle.net/about"></iframe>
</div>

Some notes - the second-row container is needed because bottom: 0 and right: 0 doesn't work on iframes for some reason. Something to do with in being a "replaced" element. But width: 100% and height: 100% works just fine. display: block is needed because it's an inline element by default and whitespace starts creating weird overflows otherwise.

Option 2 - tables. Works when you don't know the height of the first part. You can use either actual <table> tags or do it the fancy way with display: table. I'll go for the latter because it seems to be in fashion these days.

body, html {width: 100%; height: 100%; margin: 0; padding: 0}
.row-container {display: table; empty-cells: show; border-collapse: collapse; width: 100%; height: 100%;}
.first-row {display: table-row; overflow: auto; background-color: lime;}
.second-row {display: table-row; height: 100%; background-color: red; overflow: hidden }
.second-row iframe {width: 100%; height: 100%; border: none; margin: 0; padding: 0; display: block;}

<div class="row-container">
  <div class="first-row">
    <p>Some text</p>
    <p>And some more text</p>
  </div>
  <div class="second-row">
    <iframe src="https://jsfiddle.net/about"></iframe>
  </div>
</div>

Some notes - the overflow: auto makes sure that the row always includes all of its contents. Otherwise floating elements can sometimes overflow. The height: 100% on the second row makes sure it expands as much as it can squeezing the first row as small as it gets.

Recommended: Option 3 - flexbox - The cleanest one of them all.

body, html {width: 100%; height: 100%; margin: 0; padding: 0}
.row-container {display: flex; width: 100%; height: 100%; flex-direction: column; background-color: blue; overflow: hidden;}
.first-row {background-color: lime; }
.second-row { flex-grow: 1; border: none; margin: 0; padding: 0; }

<div class="row-container">
  <div class="first-row">
    <p>Some text</p>
    <p>And some more text</p>
  </div>
  <iframe src="https://jsfiddle.net/about" class="second-row"></iframe>
</div>

Some notes - the overflow: hidden is because the iframe still generates some sort of overflow even with display: block in this case. It isn't visible in the fullscreen view or the snippet editor, but the small preview window gets an extra scrollbar. No idea what that is, iframes are weird.

Solution 2 - Html

We use a JavaScript to solve this problem; here is the source.


var buffer = 20; //scroll bar buffer
var iframe = document.getElementById('ifm');

function pageY(elem) {
    return elem.offsetParent ? (elem.offsetTop + pageY(elem.offsetParent)) : elem.offsetTop;
}

function resizeIframe() {
    var height = document.documentElement.clientHeight;
    height -= pageY(document.getElementById('ifm'))+ buffer ;
    height = (height < 0) ? 0 : height;
    document.getElementById('ifm').style.height = height + 'px';
}

// .onload doesn't work with IE8 and older.
if (iframe.attachEvent) {
    iframe.attachEvent("onload", resizeIframe);
} else {
    iframe.onload=resizeIframe;
}

window.onresize = resizeIframe;

Note: ifm is the iframe ID

pageY() was created by John Resig (the author of jQuery)

Solution 3 - Html

Another way to do that would be to use the position: fixed; on parent node.
If I am not mistaken, position: fixed; ties the element to viewport, thus, once you give this node width: 100%; and height: 100%; properties, it will span over entire screen. From this point on, you can put <iframe> tag inside it and span it over remaining space (both in width and in height) with simple width: 100%; height: 100%; CSS instruction.

Example code


    body {
        margin: 0px;
        padding: 0px;
    }

    /* iframe's parent node */
    div#root {
        position: fixed;
        width: 100%;
        height: 100%;
    }

    /* iframe itself */
    div#root > iframe {
        display: block;
        width: 100%;
        height: 100%;
        border: none;
    }

   <html>
        <head>
            <title>iframe Test</title>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        </head>
        <body>
            <div id="root">
                <iframe src="http://stackoverflow.com/">
                    Your browser does not support inline frames.
                </iframe>
            </div>
        </body>
    </html>

Solution 4 - Html

Here are a few modern approaches:


The expression calc(100vh - 30px) represents the remaining height. Where 100vh is the height of the browser and the usage of calc() effectively displaces the height of the other element.

Example Here

body {
    margin: 0;
}
.banner {
    background: #f00;
    height: 30px;
}
iframe {
    display: block;
    background: #000;
    border: none;
    height: calc(100vh - 30px);
    width: 100%;
}

<div class="banner"></div>
<iframe></iframe>

Support for calc() here; support for viewport relative units here.


  • Approach 2 - Flexbox approach

Example Here

Set the display of the common parent element to flex, along with flex-direction: column (assuming you want the elements to stack on top of each other). Then set flex-grow: 1 on the child iframe element in order for it to fill the remaining space.

body {
    margin: 0;
}
.parent {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}
.parent .banner {
    background: #f00;
    width: 100%;
    height: 30px;
}
.parent iframe {
    background: #000;
    border: none;
    flex-grow: 1;
}

<div class="parent">
    <div class="banner"></div>
    <iframe></iframe>
</div>

Since this approach has less support1, I'd suggest going with the aforementioned approach.

1Though it seems to work in Chrome/FF, it doesn't work in IE (the first method works in all current browsers).

Solution 5 - Html

You can do it with DOCTYPE, but you have to use table. Check this out:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<style>
*{margin:0;padding:0}
html, body {height:100%;width:100%;overflow:hidden}
table {height:100%;width:100%;table-layout:static;border-collapse:collapse}
iframe {height:100%;width:100%}

.header {border-bottom:1px solid #000}
.content {height:100%}
</style>
</head>
<body>
<table>
	<tr><td class="header"><div><h1>Header</h1></div></td></tr>
	<tr><td class="content">
		<iframe src="http://google.com/" frameborder="0"></iframe></td></tr>
</table>
</body>
</html>

Solution 6 - Html

Maybe this has been answered already (a few answers above are "correct" ways of doing this), but I thought I'd just add my solution as well.

Our iFrame is loaded within a div, hence I needed something else then window.height. And seeing our project already relies heavily on jQuery, I find this to be the most elegant solution:

$("iframe").height($("#middle").height());

Where of course "#middle" is the id of the div. The only extra thing you'll need to do is recall this size change whenever the user resizes the window.

$(window).resize(function() {
    $("iframe").height($("#middle").height());
});

Solution 7 - Html

MichAdel code works for me but I made some minor modification to get it work properly.

function pageY(elem) {
	return elem.offsetParent ? (elem.offsetTop + pageY(elem.offsetParent)) : elem.offsetTop;
}
var buffer = 10; //scroll bar buffer
function resizeIframe() {
	var height = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight;
	height -= pageY(document.getElementById('ifm'))+ buffer ;
	height = (height < 0) ? 0 : height;
	document.getElementById('ifm').style.height = height + 'px';
}
window.onresize = resizeIframe;
window.onload = resizeIframe;

Solution 8 - Html

Here's what I did. I had the same problem and ended up searching the web for resources for hours.

<style type="text/css">
   html, body, div, iframe { margin:0; padding:0; height:100%; }
   iframe { position:fixed; display:block; width:100%; border:none; }
</style>

I added this to the head section.

Please note that my iframe is located inside the middle cell of a table that has 3 rows and 1 column.

Solution 9 - Html

Another alternative using vh

<iframe src='/' style="display:block; border:none; height:100vh; width:100%;"></iframe>

Solution 10 - Html

It's right, you are showing an iframe with 100% height respect to its container: the body.

Try this:

<body>
  <div style="width:100%; height:30px; background-color:#cccccc;">Banner</div>
  <div style="width:100%; height:90%; background-color:transparent;">
    <iframe src="http: //www.google.com.tw" style="width:100%; height:100%;">
    </iframe> 
  </div>
</body>

Of course, change the height of the second div to the height you want.

Solution 11 - Html

You can do this with html/css like this:

<body>
    <div style="width:100%; height:30px; background-color:#cccccc;">Banner</div>
    <iframe src="http: //www.google.com.tw" style="position:fixed;top:30px;bottom:0px;width:100%;"></iframe>
</body>

Solution 12 - Html

try the following:

<iframe name="" src="" width="100%" style="height: 100em"/>

it worked for me

Solution 13 - Html

New in HTML5: Use calc (on height)

<html style="width:100%; height:100%; margin: 0px; padding: 0px;">
<body style="width:100%; height:100%; margin: 0px; padding: 0px;">
<div style="width:100%; height:30px; background-color:#cccccc;">Banner</div>
<iframe src="http://www.google.com.tw" style="width:100%; height: calc(100% - 30px);"></iframe>
</body>
</html>

Solution 14 - Html

I used display:table to fix a similar issue. It almost works for this, leaving a small vertical scroll bar. If you're trying to populate that flexible column with something other than an iframe it works fine (not

Take the following HTML

<body>
  <div class="outer">
    <div class="banner">Banner</div>
    <div class="iframe-container">
      <iframe src="http: //www.google.com.tw" style="width:100%; height:100%;border:0;"></iframe>
    </div>
  </div>
</body>

Change the outer div to use display:table and ensure it has a width and height set.

.outer {
  display: table;
  height: 100%;
  width: 100%;
}

Make the banner a table-row and set its height to whatever your preference is:

.banner {
  display: table-row;
  height: 30px;
  background: #eee;
}

Add an extra div around your iframe (or whatever content you need) and make it a table-row with height set to 100% (setting its height is critical if you want to embed an iframe to fill the height)

.iframe-container {
  display: table-row;
  height: 100%;
}

Below is a jsfiddle showing it at work (without an iframe because that doesn't seem to work in the fiddle)

https://jsfiddle.net/yufceynk/1/

Solution 15 - Html

I think you have a conceptual problem here. To say "I tried set height:100% on iframe, the result is quite close but the iframe tried to fill the whole page", well, when has "100%" not been equal to "whole"?

You have asked the iframe to fill the entire height of its container (which is the body) but unfortunately it has a block level sibling in the <div> above which you've asked to be 30px big. So the parent container total is now being asked to size to 100% + 30px > 100%! Hence scrollbars.

What I think you mean is that you would like the iframe to consume what's left like frames and table cells can, i.e. height="*". IIRC this doesn't exist.

Unfortunately to the best of my knowledge there is no way to effectively mix/calculate/subtract absolute and relative units either, so I think you're reduced to two options:

  1. Absolutely position your div, which will take it out of the container so the iframe alone will consume it's containers height. This leaves you with all manner of other problems though, but perhaps for what you're doing opacity or alignment would be ok.

  2. Alternatively you need to specify a % height for the div and reduce the height of the iframe by that much. If the absolute height is really that important you'll need to apply that to a child element of the div instead.

Solution 16 - Html

Having tried the css route for a while, I ended up writing something fairly basic in jQuery that did the job for me:

function iframeHeight() {
    var newHeight = $j(window).height();
    var buffer = 180;     // space required for any other elements on the page 
    var newIframeHeight = newHeight - buffer;
    $j('iframe').css('height',newIframeHeight);    //this will aply to all iframes on the page, so you may want to make your jquery selector more specific.
}

// When DOM ready
$(function() {
    window.onresize = iframeHeight;
}

Tested in IE8, Chrome, Firefox 3.6

Solution 17 - Html

It will work with below mentioned code

<iframe src="http: //www.google.com.tw"style="position: absolute; height: 100%; border: none"></iframe>

Solution 18 - Html

Similar answer of @MichAdel, but I'm using JQuery and more elegant.

<script type="text/javascript">
    $(document).ready(function() {
        var $iframe = $('#iframe_id')[0];

        // Calculate the total offset top of given jquery element
        function totalOffsetTop($elem) {
            return $elem.offsetTop + ($elem.offsetParent ? totalOffsetTop($elem.offsetParent) : 0);
        }

        function resizeIframe() {
            var height = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight;
            height -= totalOffsetTop($iframe);
            $iframe.height = Math.max(0, height) + 'px';
        }

        $iframe.onload = resizeIframe();
        window.onresize = resizeIframe;
    });
</script>

iframe_id is the ID of the iframe tag

Solution 19 - Html

Why not do this (with minor adjustment for body padding/margins)

<script>
  var oF = document.getElementById("iframe1");
  oF.style.height = document.body.clientHeight - oF.offsetTop - 0;
</script>

Solution 20 - Html

You can do this by measuring the body size on load/resize events and setting the height to the (full height - banner height).

Note that currently in IE8 Beta2 you can't do this onresize as that event is currently broken in IE8 Beta2.

Solution 21 - Html

or you can go old-school and use a frameset perhaps:

<frameset rows="30,*">
  <frame src="banner.swf"/>
  <frame src="inner.html" />
</frameset>

Solution 22 - Html

While I agree JS seems a better option, I have a somewhat CSS only working solution. The downside of it is that if you have to add content to your iframe html document frequently, you would have to adapt one percentage trough time.

Solution:

Try not specifying any height for BOTH your html documents,

html, body, section, main-div {}

then only code this:

#main-div {height:100%;}
#iframe {height:300%;}

note: the div should be your main section.

This should relatively work. the iframe does exactly calculates 300% of the visible window height. If you html content from the 2nd document (in the iframe) is smaller in height than 3 times your browser height, it works. If you don't need to add content frequently to that document this is a permanent solution and you could just find your own % needed according to your content height.

This works because it prevents the 2nd html document (the one embed) to inherit its height frome the parent html document. It prevents it because we didn't specify an height for both of them. When we give a % to the child it looks for its parent, if not, it takes its content height. And only if the other containers aren't given heights, from what I tried.

Solution 23 - Html

The "seamless" attribute is a new standard aiming to solve this issue:

http://www.w3schools.com/tags/att_iframe_seamless.asp

When assigning this attribute it will remove borders and scroll bars and size the iframe to its content size. though it is only supported in Chrome and latest Safari

more on this here: https://stackoverflow.com/questions/4804604/html5-iframe-seamless-attribute

Solution 24 - Html

A simple jQuery solution

Use this in a script inside the iframed page

$(function(){

	if(window != top){
		var autoIframeHeight = function(){
			var url = location.href;
			$(top.jQuery.find('iframe[src="'+ url +'"]')).css('height', $('body').height()+4);
		}
		$(window).on('resize',autoIframeHeight);
		autoIframeHeight();
	}

}

Solution 25 - Html

you cant set the iframe height in % because your parent body height is not 100% so make the parent height as 100% and then apply iframe height 100%

For eg.
<html>
<head>
<style>
html,body{height:100%}
</style> 
</head>
<body>
<iframe src="http://www.quasarinfosystem.com" height="100%" width="100%" ></iframe>
</body>
</html>

Solution 26 - Html

If you have access to the content of the iframe that will be loaded, you can tell its parent to resize whenever it resizes..

	$(window).resize(function() {
	    $(parent.document)
            .find("iframe")
            .css("height", $("body").css("height"));		
    }).trigger("resize");

If you have more than one iframe on the page, you may need to use id's or other clever methods to enhance .find("iframe") so that you're selecting the correct one.

Solution 27 - Html

I think the best way to achieve this scenario using css position. set position relative to your parent div and position:absolute to your iframe.

.container{
  width:100%;
  position:relative;
  height:500px;
}

iframe{
  position:absolute;
  width:100%;
  height:100%;
}

<div class="container">
  <iframe src="http://www.w3schools.com">
  <p>Your browser does not support iframes.</p>
 </iframe>
</div>

for other padding and margin issue now a days css3 calc() is very advanced and mostly compatible to all browser as well.

check calc()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDarkthreadView Question on Stackoverflow
Solution 1 - HtmlVilx-View Answer on Stackoverflow
Solution 2 - HtmlMichAdelView Answer on Stackoverflow
Solution 3 - HtmlD1SoveRView Answer on Stackoverflow
Solution 4 - HtmlJosh CrozierView Answer on Stackoverflow
Solution 5 - HtmlducuView Answer on Stackoverflow
Solution 6 - HtmlTim GeertsView Answer on Stackoverflow
Solution 7 - HtmlasimrafiView Answer on Stackoverflow
Solution 8 - HtmlDanut MileaView Answer on Stackoverflow
Solution 9 - HtmlmontrealmikeView Answer on Stackoverflow
Solution 10 - HtmlARemesalView Answer on Stackoverflow
Solution 11 - HtmlvdbuilderView Answer on Stackoverflow
Solution 12 - HtmlsreeView Answer on Stackoverflow
Solution 13 - HtmlStefan SteigerView Answer on Stackoverflow
Solution 14 - HtmldaamsieView Answer on Stackoverflow
Solution 15 - HtmlannakataView Answer on Stackoverflow
Solution 16 - HtmlbenbView Answer on Stackoverflow
Solution 17 - HtmlmgrView Answer on Stackoverflow
Solution 18 - HtmlRoy ShmuliView Answer on Stackoverflow
Solution 19 - Htmlaccess_grantedView Answer on Stackoverflow
Solution 20 - HtmlscunliffeView Answer on Stackoverflow
Solution 21 - HtmlAmir AradView Answer on Stackoverflow
Solution 22 - HtmlpixelfeView Answer on Stackoverflow
Solution 23 - Htmluser2254487View Answer on Stackoverflow
Solution 24 - HtmlunlocoView Answer on Stackoverflow
Solution 25 - HtmlPravin AbhaleView Answer on Stackoverflow
Solution 26 - HtmlStephenView Answer on Stackoverflow
Solution 27 - HtmlJay PatelView Answer on Stackoverflow