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.