Faça o Iframe caber 100% da altura restante do contêiner


260

Quero criar uma página da web com um banner e um iframe. Espero que o iframe possa preencher toda a altura restante da página e ser redimensionado automaticamente à medida que o navegador estiver redimensionando. É possível fazê-lo sem escrever código Javascript, apenas com CSS?

Tentei definir o height:100%iframe, o resultado é bem próximo, mas o iframe tentou preencher toda a altura da página, incluindo a 30pxaltura do elemento div do banner, então obtive uma barra de rolagem vertical desnecessária. Não é perfeito.

Notas da atualização : desculpe-me por não descrever bem a pergunta. Tentei a margem CSS, preenchendo o atributo no DIV para ocupar toda a altura restante de uma página da Web com êxito, mas o truque não funcionou no 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>

Qualquer idéia é apreciada.

Respostas:


236

Atualização em 2019

TL; DR: Hoje, a melhor opção é a última nesta resposta - flexbox. Tudo suporta bem e tem há anos. Vá em frente e não olhe para trás. O restante desta resposta é deixado por razões históricas.


O truque é entender do que os 100% são tirados. A leitura de especificações CSS pode ajudá-lo lá.

Para resumir uma longa história - existe um "bloco contendo" - que não é necessário como elemento pai. Simplificando, é o primeiro elemento na hierarquia que possui posição: relativa ou posição: absoluta. Ou o próprio elemento do corpo, se não houver mais nada. Portanto, quando você diz "width: 100%", ele verifica a largura do "bloco contendo" e define a largura do seu elemento para o mesmo tamanho. Se houver mais alguma coisa lá, você poderá obter o conteúdo de um "bloco contendo" maior que ele (portanto, "transbordando").

Altura funciona da mesma maneira. Com uma exceção. Você não pode obter altura para 100% da janela do navegador. O elemento de nível mais alto, contra o qual 100% pode ser calculado, é o elemento body (ou html? Não tenho certeza), e se estende apenas o suficiente para conter seu conteúdo. Especificar altura: 100% não terá efeito, pois não possui "elemento pai" contra o qual medir 100%. A janela em si não conta. ;)

Para fazer algo esticar exatamente 100% da janela, você tem duas opções:

  1. Use JavaScript
  2. Não use DOCTYPE. Essa não é uma boa prática, mas coloca os navegadores no "modo quirks", no qual você pode fazer height = "100%" nos elementos e os estenderá ao tamanho da janela. Observe que o restante da sua página provavelmente precisará ser alterado também para acomodar as alterações do DOCTYPE.

Atualização: não tenho certeza se eu não estava errado quando publiquei isso, mas isso certamente está desatualizado agora. Hoje, você pode fazer isso na sua folha de estilo: html, body { height: 100% }e isso realmente se estenderá a toda a sua janela de visualização. Mesmo com um DOCTYPE. min-height: 100%também pode ser útil, dependendo da sua situação.

E eu também não aconselharia ninguém a fazer um documento em modo peculiar , porque causa muito mais dores de cabeça do que os resolve. Todo navegador possui um modo quirks diferente; portanto, tornar a página com aparência consistente nos navegadores se torna duas ordens de magnitude mais difíceis. Use um DOCTYPE. Sempre. De preferência o HTML5 - <!DOCTYPE html>. É fácil de lembrar e funciona como um encanto em todos os navegadores, mesmo nos 10 anos de idade.

A única exceção é quando você precisa oferecer suporte a algo como IE5 ou algo assim. Se você estiver lá, estará sozinho de qualquer maneira. Esses navegadores antigos não são nada parecidos com os navegadores atuais, e poucos conselhos que são dados aqui o ajudarão. Pelo lado positivo, se você estiver lá, provavelmente precisará suportar UM tipo de navegador, o que elimina os problemas de compatibilidade.

Boa sorte!

Atualização 2: Ei, faz muito tempo! 6 anos depois, novas opções estão em cena. Acabei de ter uma discussão nos comentários abaixo. Aqui estão mais truques para você que funcionam nos navegadores de hoje.

Opção 1 - posicionamento absoluto. Agradável e limpo para quando você conhece a altura exata da primeira peça.

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>

Algumas notas - o second-rowrecipiente é necessária porque bottom: 0e right: 0não funciona em iframe, por algum motivo. Algo a ver com ser um elemento "substituído". Mas width: 100%e height: 100%funciona muito bem. display: blocké necessário porque é um inlineelemento por padrão e o espaço em branco começa a criar estouros estranhos caso contrário.

Opção 2 - tabelas. Funciona quando você não conhece a altura da primeira parte. Você pode usar <table>tags reais ou fazê-lo da maneira mais sofisticada possível display: table. Eu vou para o último, porque parece estar na moda nos dias de hoje.

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>

Algumas notas - overflow: autogarante que a linha sempre inclua todo o seu conteúdo. Caso contrário, os elementos flutuantes às vezes podem transbordar. A height: 100%segunda linha garante que ela se expanda o máximo que puder, espremendo a primeira linha o menor possível.

Opção 3 - flexbox. O mais limpo de todos, mas com um suporte menos que estelar ao navegador. O IE10 precisará de -ms-prefixos para as propriedades do flexbox e qualquer coisa menos não será compatível com isso.

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>

Algumas notas - isso overflow: hiddenocorre porque o iframe ainda gera algum tipo de estouro, mesmo display: blocknesse caso. Não é visível na visualização em tela cheia ou no editor de trechos, mas a pequena janela de visualização recebe uma barra de rolagem extra. Não faço ideia do que é isso, iframes são estranhos.


@sproketboy Bem, é uma recomendação do W3C. E nem é o pior, nem por um longo caminho.
— John

Então, colocamos isso na folha de estilo da página do IFrame ou na folha de estilo da página pai que contém o IFrame?
— Mathias Lykkegaard Lorenzen /

1
Isso é demais, obrigado! O flexbox o mais limpos de fato, mas as mesas também são grandes para aprender e parecem funcionar sem os excessos: jsfiddle.net/dmitri14/1uqh3zgx/2
— Dmitri Zaitsev

1
Pode valer a pena mover as atualizações mais recentes para o topo desta resposta. Eu tive que passar por tudo para obter a melhor resposta, flexbox.
— forgivenson

2
@forgivenson - É verdade. Adicionada uma nota no início desta resposta.
— Vilx-

68

Usamos um JavaScript para resolver esse problema; aqui está a fonte.


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;

Nota: ifmé o ID do iframe

pageY() foi criado por John Resig (o autor do jQuery)


49

Outra maneira de fazer isso seria usar o position: fixed;nó pai.
Se não me engano, position: fixed;vincula o elemento à viewport; assim, depois de fornecer esse nó width: 100%;e height: 100%;propriedades, ele se estenderá por toda a tela. A partir deste ponto, você pode colocar a <iframe>tag dentro dela e estendê-la pelo espaço restante (em largura e altura) com simples width: 100%; height: 100%;instruções CSS.

Código de exemplo


    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>


1
Como isso está levando a altura "restante" ..?
— EricG

3
Notei que você também precisa adicionar position: fixedao iframe.
— 0xF 18/06

obrigado, corrigi meu relatório do SSRS, evite suicídio por mais um dia.
— Mike D

1
não há barras de rolagem visível
— Andrej

aperfeiçoar - você poderia explicar o css '>' ex div # root> iframe furtheras Eu estou familiarizado com ele e não pode encontrar referência
— Datadimension

40

Aqui estão algumas abordagens modernas:



  • Abordagem 2 - Abordagem Flexbox

    Exemplo Aqui

    Defina o displayelemento pai comum como flex, junto com flex-direction: column(supondo que você queira que os elementos sejam empilhados uns sobre os outros). Em seguida, defina flex-grow: 1o iframeelemento filho para que ele preencha o espaço restante.

    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>

    Como essa abordagem tem menos suporte 1 , sugiro seguir a abordagem mencionada acima.

1 Embora pareça funcionar no Chrome / FF, não funciona no IE (o primeiro método funciona em todos os navegadores atuais).


3
Tanto no trabalho quanto na IMO, as duas opções mencionadas aqui são a melhor abordagem. Eu prefiro a flexboxopção porque com calcvocê precisa saber a quantidade de espaço a deduzir do vh. Com flexboxum simples flex-grow:1faz.
— Kilmazing

39

Você pode fazer isso com DOCTYPE, mas precisa usar table. Veja isso:

<!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>

1
pelo menos não precisa de js !! mas é seguro para a web?
— Ali Shakiba

1
A desvantagem dessa solução é que o html body {overflow: hidden;} removerá os pergaminhos da página.
— Ali Shakiba

Estou tentando adicionar rodapé no código acima, mas o rodapé não está aparecendo. Você pode por favor ajudar.
— Akshay Raut

18

Talvez isso já tenha sido respondido (algumas respostas acima são formas "corretas" de fazer isso), mas pensei em adicionar minha solução também.

Nosso iFrame é carregado dentro de uma div, portanto, eu precisava de algo mais do que window.height. E vendo o nosso projeto já depende muito do jQuery, acho que essa é a solução mais elegante:

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

Onde é claro que "#middle" é o ID da div. A única coisa extra que você precisa fazer é recuperar essa alteração de tamanho sempre que o usuário redimensionar a janela.

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

7

Aqui está o que eu fiz. Eu tive o mesmo problema e acabei pesquisando recursos na web por horas.

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

Eu adicionei isso à seção principal.

Observe que meu iframe está localizado dentro da célula do meio de uma tabela que possui 3 linhas e 1 coluna.


Seu código funcionará apenas o TD que contém o IFRAME tem altura: 100%. Funcionará se a tabela estiver contida em um elemento DIV, porque você tem um estilo para todas as divs terem altura: 100%.
— Nikola Petkanski

6

O código MichAdel funciona para mim, mas eu fiz algumas pequenas modificações para fazê-lo funcionar corretamente.

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;

4

Está certo, você está mostrando um iframe com 100% de altura em relação ao seu contêiner: o corpo.

Tente o seguinte:

<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>

Evidentemente, altere a altura da segunda div para a altura desejada.


8
30px + 90%! = 100%
— stepancheg 29/11

1
Pode usar calc (100% - 30px) em vez de 90%
— Justin E

4

tente o seguinte:

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

funcionou para mim


4
Não preenche o pai, apenas coloca uma grande altura no iframe.
— Ben

3

Você pode fazer isso com html / css assim:

<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>

2

Novo no HTML5: use calc (na altura)

<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>

2

Eu usei display: table para corrigir um problema semelhante. É quase funciona para isso, deixando uma pequena barra de rolagem vertical. Se você está tentando preencher essa coluna flexível com algo diferente de um iframe, funciona bem (não

Pegue o seguinte 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>

Altere a div externa para usar display: table e verifique se a largura e a altura estão definidas.

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

Torne o banner uma linha da tabela e defina sua altura para qualquer que seja sua preferência:

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

Adicione uma div extra ao redor do seu iframe (ou qualquer conteúdo que você precise) e torne-o uma linha de tabela com altura definida como 100% (definir sua altura é essencial se você deseja incorporar um iframe para preencher a altura)

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

Abaixo está um jsfiddle mostrando-o no trabalho (sem um iframe porque isso não parece funcionar no violino)

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


1

Eu acho que você tem um problema conceitual aqui. Para dizer "Tentei definir a altura: 100% no iframe, o resultado está bem próximo, mas o iframe tentou preencher a página inteira" , bem, quando "100%" não foi igual a "todo"?

Você pediu ao iframe para preencher toda a altura do contêiner (que é o corpo), mas infelizmente ele tem um irmão no nível de bloco no <div> acima do qual você pediu 30px de tamanho. Agora, o total do contêiner pai está sendo solicitado a dimensionar para 100% + 30px> 100%! Daí barras de rolagem.

O que eu acho que você quer dizer é que você gostaria que o iframe consumisse o que resta como quadros e células da tabela, ou seja, height = "*". IIRC isso não existe.

Infelizmente, até onde sei, também não há como misturar / calcular / subtrair efetivamente unidades absolutas e relativas, então acho que você está reduzido a duas opções:

  1. Posicione absolutamente sua div, que a retirará do contêiner, de modo que somente o iframe consuma a altura do contêiner. Isso deixa você com todos os tipos de outros problemas, mas talvez o que você está fazendo opacidade ou alinhamento esteja ok.

  2. Como alternativa, você precisa especificar uma% de altura para a div e reduzir em muito a altura do iframe. Se a altura absoluta for realmente tão importante, você precisará aplicá-la a um elemento filho da div.


1

Tendo tentado a rota css por um tempo, acabei escrevendo algo bastante básico no jQuery que fez o trabalho para mim:

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;
}

Testado no IE8, Chrome, Firefox 3.6


1

Ele funcionará com o código abaixo mencionado

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

1

Resposta semelhante do @MichAdel, mas estou usando o JQuery e mais elegante.

<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 é o ID da tag iframe


0

Você pode fazer isso medindo o tamanho do corpo em eventos de carregamento / redimensionamento e configurando a altura para (altura total - altura do banner).

Observe que atualmente no IE8 Beta2 você não pode fazer isso em redimensionamento, pois esse evento está quebrado no IE8 Beta2.


0

ou você pode ir à moda antiga e usar um conjunto de quadros, talvez:

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

2
@vdbuilder: Não, é apenas pré-html5 válido . Aposto que ainda funciona. ;-)
— TJ Crowder

0

Embora eu concorde que o JS parece uma opção melhor, eu tenho uma solução que funciona apenas com CSS. A desvantagem disso é que, se você precisar adicionar conteúdo ao seu documento HTML iframe com frequência, precisará adaptar uma porcentagem durante o tempo.

Solução:

Tente não especificar nenhuma altura para AMBOS os seus documentos html,

html, body, section, main-div {}

codifique apenas isso:

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

nota: a div deve ser sua seção principal.

Isso deve funcionar relativamente. o iframe calcula exatamente 300% da altura da janela visível. Se o conteúdo html do 2º documento (no iframe) tiver uma altura menor que 3 vezes a altura do navegador, ele funcionará. Se você não precisar adicionar conteúdo com frequência a esse documento, essa é uma solução permanente e você poderá encontrar a% necessária, de acordo com a altura do conteúdo.

Isso funciona porque evita que o segundo documento html (aquele incorporado) herda sua altura do documento html pai. Isso evita porque não especificamos uma altura para os dois. Quando damos um% ao filho, ele procura seu pai, caso contrário, ele assume a altura do conteúdo. E somente se os outros contêineres não tiverem alturas, pelo que tentei.



0

Uma solução simples jQuery

Use isso em um script dentro da página iframed

$(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();
    }

}

0

você não pode definir a altura do iframe em% porque a altura do corpo do pai não é 100%. Portanto, torne a altura do pai como 100% e aplique a altura do iframe 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>

0

Se você tiver acesso ao conteúdo do iframe que será carregado, poderá solicitar que o pai seja redimensionado sempre que ele for redimensionado.

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

Se você tiver mais de um iframe na página, poderá ser necessário usar IDs ou outros métodos inteligentes para aprimorar .find ("iframe") para selecionar o correto.


0

Eu acho que a melhor maneira de alcançar esse cenário usando a posição css. defina a posição em relação ao div principal e a posição: absoluta ao 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>

para outros problemas de preenchimento e margem nos dias de hoje, o css3 calc () é muito avançado e também compatível com todos os navegadores.

verifique calc ()


0

Por que não fazer isso (com pequenos ajustes para preenchimento / margens do corpo)

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

Você precisa substituir -0por +'px'no final. Funciona no celular?
— Dmitri Záitsev
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.