dinamize a altura do iframe com base no conteúdo interno - JQUERY / Javascript

202

Estou carregando uma página da web aspx em um iframe. O conteúdo do Iframe pode ter mais altura que a altura do iframe. O iframe não deve ter barras de rolagem.

Eu tenho uma divtag wrapper dentro do iframe, que basicamente é todo o conteúdo. Eu escrevi alguns jQuery para fazer o redimensionamento acontecer:

$("#TB_window", window.parent.document).height($("body").height() + 50);

onde TB_windowé a div na qual Iframeestá contida.

body - a etiqueta do corpo do aspx no iframe.

Este script está anexado ao conteúdo do iframe. Estou recebendo o TB_windowelemento da página pai. Enquanto isso funciona bem no Chrome, mas o TB_window entra em colapso no Firefox. Estou realmente confuso / perdido por que isso acontece.

karry
fonte
essa página iframe .aspx é do mesmo nome de domínio?
187 AlexC
você pode verificar $ ("body"). height () tem um valor no firefox?
Michael L Watson
yes..the iframe está no mesmo domínio que o recipiente principal
karry
@MichaelLWatson Parece que a janela relógio firebug tem o valor como 0 para a altura do corpo ... Chrome tem um valor embora
karry
Angular iFrame exemplo Auto-height: gitlab.com/reduardo7/angular-iframe-auto-height
Eduardo Cuomo

Respostas:

212

Você pode recuperar a altura do IFRAMEconteúdo usando: contentWindow.document.body.scrollHeight

Após o IFRAMEcarregamento, você pode alterar a altura fazendo o seguinte:

<script type="text/javascript">
  function iframeLoaded() {
      var iFrameID = document.getElementById('idIframe');
      if(iFrameID) {
            // here you can make the height, I delete it first, then I make it again
            iFrameID.height = "";
            iFrameID.height = iFrameID.contentWindow.document.body.scrollHeight + "px";
      }   
  }
</script>   

Em seguida, na IFRAMEtag, você conecta o manipulador da seguinte maneira:

<iframe id="idIframe" onload="iframeLoaded()" ...

Eu tinha uma situação há um tempo atrás, onde eu também precisava chamar iframeLoadeda partir da IFRAMEprópria depois de um formulário de submissão ocorreu dentro. Você pode fazer isso fazendo o seguinte nos IFRAMEscripts de conteúdo:

parent.iframeLoaded();
Aristos
fonte
153
Não suporta em vários domínios.
Soumya
3
@Soumya O domínio cruzado não tem nada a ver com esse código. Há um problema de segurança que você ignora com um comando.
Aristos
9
@Soumya Procure X-FRAME-OPTIONSadicionar uma linha como: Response.AddHeader("X-FRAME-OPTIONS", "SAMEORIGIN");ouresponse.addHeader("X-FRAME-OPTIONS", "Allow-From https://some.othersite.com");
Aristos
15
Isso resolve a cruz iframe domínio questão dimensionamento github.com/davidjbradshaw/iframe-resizer
David Bradshaw
2
@ débs Você também pode tentar mudar iFrameID.height = "";para iFrameID.height = "20px";. A altura padrão do iframe do navegador é 150px, e é para isso que ""ela é redefinida.
philfreo
112

Uma resposta ligeiramente melhorada para Aristos ...

<script type="text/javascript">
  function resizeIframe(iframe) {
    iframe.height = iframe.contentWindow.document.body.scrollHeight + "px";
  }
</script>  

Em seguida, declare no seu iframe da seguinte maneira:

<iframe onload="resizeIframe(this)" ...

Existem duas pequenas melhorias:

  1. Você não precisa obter o elemento via document.getElementById - como já o possui no retorno de chamada onload.
  2. Não há necessidade de definir iframe.height = ""se você vai redesigná-lo na próxima declaração. Fazer isso gera uma sobrecarga, pois você está lidando com um elemento DOM.

Editar: se o conteúdo do quadro estiver sempre mudando, chame:

parent.resizeIframe(this.frameElement); 

de dentro do iframe após a atualização. Trabalhos para a mesma origem.

Ou para detectar automaticamente:

  // on resize
  this.container = this.frameElement.contentWindow.document.body;

  this.watch = () => {
    cancelAnimationFrame(this.watcher);

    if (this.lastScrollHeight !== container.scrollHeight) {
      parent.resizeIframeToContentSize(this.frameElement);  
    }
    this.lastScrollHeight = container.scrollHeight;
    this.watcher = requestAnimationFrame(this.watch);
  };
  this.watcher = window.requestAnimationFrame(this.watch);
Anchova
fonte
6
O que você faria se o conteúdo no quadro estivesse sempre mudando?
22413 Kevin
Se o tamanho do conteúdo continuar mudando e / ou se o seu iframe for projetado para ficar em outros domínios que não sejam o domínio em que o iframe puxa a página, será necessário fazer algo diferente.
BlueFish
4
Para isso ... a solução é usar postMessage e receiveMessage. Resolvi
BlueFish
A idéia é calcular a nova altura e enviar uma mensagem ao quadro pai, que precisa receber a mensagem e ajustar a altura do iframe de acordo.
BlueFish
Sempre foram alguns Pixels curtos para mim, então eu vim com isso: # function resizeIframe(iframe) { var size=iframe.contentWindow.document.body.scrollHeight; var size_new=size+20; iframe.height = size_new + "px"; }
Martin Mühl
56

Descobri que a resposta aceita não era suficiente, pois X-FRAME-OPTIONS: Allow-From não é suportado no safari ou no chrome . Em vez disso, adotamos uma abordagem diferente, encontrada em uma apresentação de Ben Vinegar, da Disqus. A idéia é adicionar um ouvinte de evento à janela pai e, dentro do iframe, use window.postMessage para enviar um evento ao pai solicitando que ele faça alguma coisa (redimensione o iframe).

Portanto, no documento pai, adicione um ouvinte de evento:

window.addEventListener('message', function(e) {
  var $iframe = jQuery("#myIframe");
  var eventName = e.data[0];
  var data = e.data[1];
  switch(eventName) {
    case 'setHeight':
      $iframe.height(data);
      break;
  }
}, false);

E dentro do iframe, escreva uma função para postar a mensagem:

function resize() {
  var height = document.getElementsByTagName("html")[0].scrollHeight;
  window.parent.postMessage(["setHeight", height], "*"); 
}

Por fim, dentro do iframe, adicione um onLoad à tag body para disparar a função redimensionar:

<body onLoad="resize();">
Marty Mulligan
fonte
1
Para que isso funcionasse para mim, tive que mudar "window.parent" para apenas "parent".
prograhammer
Ótimo! mas apenas carrega a altura uma vez. Se você quiser fazer o iframe verdadeiramente responsivo eu prefiro chamar o método de redimensionamento cada segundo, assim:setInterval(resize, 1000);
Jules Colle
12

Adicione isso ao iframe, isso funcionou para mim:

onload="this.height=this.contentWindow.document.body.scrollHeight;"

E se você usa o jQuery, tente este código:

onload="$(this).height($(this.contentWindow.document.body).find(\'div\').first().height());"
Mohit Aneja
fonte
6

Você pode ver quatro propriedades diferentes para obter a altura do conteúdo em um iFrame.

document.documentElement.scrollHeight
document.documentElement.offsetHeight
document.body.scrollHeight
document.body.offsetHeight

Infelizmente, todos eles podem dar respostas diferentes e estas são inconsistentes entre os navegadores. Se você definir a margem do corpo como 0, a document.body.offsetHeightresposta será a melhor. Para obter o valor correto, tente esta função; que é extraído da biblioteca iframe-redizer , que também cuida de manter o iFrame do tamanho correto quando o conteúdo é alterado ou o navegador é redimensionado.

function getIFrameHeight(){
    function getComputedBodyStyle(prop) {
        function getPixelValue(value) {
            var PIXEL = /^\d+(px)?$/i;

            if (PIXEL.test(value)) {
                return parseInt(value,base);
            }

            var 
                style = el.style.left,
                runtimeStyle = el.runtimeStyle.left;

            el.runtimeStyle.left = el.currentStyle.left;
            el.style.left = value || 0;
            value = el.style.pixelLeft;
            el.style.left = style;
            el.runtimeStyle.left = runtimeStyle;

            return value;
        }

        var 
            el = document.body,
            retVal = 0;

        if (document.defaultView && document.defaultView.getComputedStyle) {
            retVal =  document.defaultView.getComputedStyle(el, null)[prop];
        } else {//IE8 & below
            retVal =  getPixelValue(el.currentStyle[prop]);
        } 

        return parseInt(retVal,10);
    }

    return document.body.offsetHeight +
        getComputedBodyStyle('marginTop') +
        getComputedBodyStyle('marginBottom');
}
David Bradshaw
fonte
Isso não funciona com itens que "rolam", por exemplo, tabelas de dados ou divs flutuantes. A altura é baseada em qualquer que seja a altura normal desenrolada e não na altura final.
djack109
@ djack109 provavelmente algo em seu CSS pára um elemento encolhendo na sua página
David Bradshaw
3

Outras respostas não estavam funcionando para mim, então eu fiz algumas alterações. Espero que isso ajude

$('#iframe').on("load", function() {
    var iframe = $(window.top.document).find("#iframe");
    iframe.height(iframe[0].ownerDocument.body.scrollHeight+'px' );
});
Ravi
fonte
2

Em vez de usar javscript / jquery, a maneira mais fácil que encontrei é:

<iframe style="min-height:98vh" src="http://yourdomain.com" width="100%"></iframe>

Aqui 1vh = 1% da altura da janela do navegador. Portanto, o valor teórico da altura a ser definida é 100vh, mas praticamente 98vh fez a mágica.

Binod
fonte
9
Isso não leva em consideração a altura do conteúdo do iframe.
Adrian Pauly
Isto torna-se perto o suficiente quando você não tem uma maneira simples de contornar o drama de domínio cruzado ...
dsghi
2

Caso isso ajude alguém. Eu estava puxando meu cabelo tentando fazer isso funcionar, então notei que o iframe tinha uma entrada na classe com altura: 100%. Quando eu removi isso, tudo funcionou como esperado. Portanto, verifique se há conflitos de CSS.

user8640976
fonte
2

você também pode adicionar requestAnimationFrame repetido ao seu resizeIframe (por exemplo, da resposta do @ BlueFish), que sempre seria chamado antes do navegador pintar o layout e você poderia atualizar a altura do iframe quando seu conteúdo mudasse de altura. por exemplo, formulários de entrada, conteúdo carregado lento etc.

<script type="text/javascript">
  function resizeIframe(iframe) {
    iframe.height = iframe.contentWindow.document.body.scrollHeight + "px";
    window.requestAnimationFrame(() => resizeIframe(iframe));
  }
</script>  

<iframe onload="resizeIframe(this)" ...

seu retorno de chamada deve ser rápido o suficiente para não causar grande impacto em seu desempenho geral

user2520818
fonte
1
Esta é uma solução muito eficiente que, desde os testes iniciais, funciona muito bem. Eu estaria interessado nas implicações de desempenho de usar isso.
KFE
Acabei de encontrar um caso Uncaught TypeError: Cannot read property 'scrollHeight' of null pois bodyé null, no entanto, funciona normalmente.
caot
1

Estou usando jQuery e o código abaixo está funcionando para mim,

var iframe = $(window.top.document).find("#iframe_id_here");
iframe.height(iframe.contents().height()+'px' );
srijishks
fonte
0

Eu encontrei a resposta de Troy não funcionou. Este é o mesmo código reformulado para o ajax:

$.ajax({                                      
    url: 'data.php',    
    dataType: 'json',                             

    success: function(data)
    {
        // Put the data onto the page

        // Resize the iframe
        var iframe = $(window.top.document).find("#iframe");
        iframe.height( iframe[0].contentDocument.body.scrollHeight+'px' );
    }
});
Martin Lester
fonte
0

Para adicionar ao pedaço de janela que parece cortado na parte inferior, especialmente quando você não tem rolagem, usei:

function resizeIframe(iframe) {
    var addHeight = 20; //or whatever size is being cut off
    iframe.height = iframe.contentWindow.document.body.scrollHeight + addHeight + "px";
  }
Matt Stacey
fonte
0

Essa é útil quando você precisa de uma solução sem jquery. Nesse caso, você deve tentar adicionar um contêiner e definir um preenchimento para ele em porcentagens

Código de exemplo HTML:

<div class="iframecontainer">
    <iframe scrolling="no" src="..." class="iframeclass"width="999px" height="618px"></iframe>
</div>

Código de exemplo CSS:

.iframeclass{
    position: absolute;
    top: 0;
    width: 100%;
}

.iframecontainer{
    position: relative;
    width: 100%;
    height: auto;
    padding-top: 61%;
}
Juan M
fonte
0

A solução simples é medir a largura e a altura da área de conteúdo e, em seguida, usar essas medidas para calcular a porcentagem de preenchimento inferior.

Nesse caso, as medidas são 1680 x 720 px; portanto, o preenchimento na parte inferior é 720/1680 = 0,43 * 100, o que resulta em 43%.

.canvas-container {    
    position: relative;
    padding-bottom: 43%; // (720 ÷ 1680 = 0.4286 = 43%)
    height: 0;
    overflow: hidden;   
}

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

Uma resposta ligeiramente melhorada para o BlueFish ...

function resizeIframe(iframe) {
    var padding = 50;
    if (iframe.contentWindow.document.body.scrollHeight < (window.innerHeight - padding))
        iframe.height = iframe.contentWindow.document.body.scrollHeight + "px";
    else
        iframe.height = (window.innerHeight - padding) + "px";
}

Isso leva em consideração a altura da tela do Windows (navegador, telefone), que é boa para design responsivo e iframes que têm uma altura enorme. Preenchimento representa o preenchimento que você deseja acima e abaixo do iframe, no caso de passar pela tela inteira.

Tadej Vengust
fonte
0
jQuery('.home_vidio_img1 img').click(function(){
    video = '<iframe src="'+ jQuery(this).attr('data-video') +'"></iframe>';
    jQuery(this).replaceWith(video);
});

jQuery('.home_vidio_img2 img').click(function(){
    video = <iframe src="'+ jQuery(this).attr('data-video') +'"></iframe>;
    jQuery('.home_vidio_img1 img').replaceWith(video);
    jQuery('.home_vidio_img1 iframe').replaceWith(video);
});

jQuery('.home_vidio_img3 img').click(function(){
    video = '<iframe src="'+ jQuery(this).attr('data-video') +'"></iframe>';
    jQuery('.home_vidio_img1 img').replaceWith(video);
    jQuery('.home_vidio_img1 iframe').replaceWith(video);
});

jQuery('.home_vidio_img4 img').click(function(){
    video = '<iframe src="'+ jQuery(this).attr('data-video') +'"></iframe>';
    jQuery('.home_vidio_img1 img').replaceWith(video);
    jQuery('.home_vidio_img1 iframe').replaceWith(video);
});
Keyur Savsani
fonte
0

Exemplo usando PHP htmlspecialchars () + verifique se a altura existe e é> 0:

$my_html_markup = ''; // Insert here HTML markup with CSS, JS... '<html><head></head><body>...</body></html>'
$iframe = '<iframe onload="if(this.contentWindow.document.body.scrollHeight) {this.height = this.contentWindow.document.body.scrollHeight;}" width="100%" src="javascript: \''. htmlspecialchars($my_html_markup) . '\'"></iframe>';
jteks
fonte
0

basta posicionar o contêiner iframe: absoluto e o iframe alterará automaticamente sua altura de acordo com seu conteúdo

<style>
   .iframe-container {
       display: block;
       position: absolute;
       /*change position as you need*/
       bottom: 0;
       left: 0;
       right: 0;
       top: 0;
   }
   iframe {
       margin: 0;
       padding: 0;
       border: 0;
       width: 100%;
       background-color: #fff;
   }
 </style>
 <div class="iframe-container">
     <iframe src="http://iframesourcepage"></iframe>
 </div>
Hatem Badawi
fonte
-1
$(document).height() // - $('body').offset().top

e / ou

$(window).height()

Consulte a pergunta Estouro de pilha Como obter a altura de um elemento do corpo .

Tente isso para encontrar a altura do corpo no jQuery:

if $("body").height()

Não tem um valor se o Firebug . Talvez seja esse o problema.

Michael L Watson
fonte
Eu tentei fazer as duas coisas ... ainda acontece no Firefox. O firefox de alguma forma não obtém o window.height () no iframe. Como eu mencionei, o script está anexado ao conteúdo Iframe e eu estou chamando-o no document.ready () função
karry