haga que la altura del iframe sea dinámica en función del contenido interno: JQUERY / Javascript

202

Estoy cargando una página web aspx en un iframe. El contenido en el iframe puede ser más alto que la altura del iframe. El iframe no debe tener barras de desplazamiento.

Tengo una divetiqueta de contenedor dentro del iframe que básicamente es todo el contenido. Escribí algo de jQuery para que el cambio de tamaño suceda:

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

¿Dónde TB_windowestá el div en el que Iframeestá contenido?

body - la etiqueta del cuerpo del aspx en el iframe.

Este script se adjunta al contenido del iframe. Estoy obteniendo el TB_windowelemento de la página principal. Si bien esto funciona bien en Chrome, pero la ventana TB_ se derrumba en Firefox. Estoy realmente confundido / perdido sobre por qué sucede eso.

karry
fuente
esa página de iframe .aspx es del mismo nombre de dominio?
AlexC
¿puedes comprobar que $ ("body"). height () tiene un valor en firefox?
Michael L Watson
sí .. el iframe está en el mismo dominio que la página del contenedor
karry
@MichaelLWatson Parece que la ventana de vigilancia de Firebug tiene el valor 0 para la altura del cuerpo ... Sin embargo, Chrome tiene un valor
karry
Ejemplo de altura automática de iFrame angular: gitlab.com/reduardo7/angular-iframe-auto-height
Eduardo Cuomo el

Respuestas:

212

Puede recuperar la altura del IFRAMEcontenido de 's utilizando: contentWindow.document.body.scrollHeight

Después de que IFRAMEse cargue, puede cambiar la altura haciendo lo siguiente:

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

Luego, en la IFRAMEetiqueta, conecta el controlador de esta manera:

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

Tuve una situación hace un tiempo en la que además necesitaba llamar iframeLoadeddesde el IFRAMEmismo después de que ocurriera un envío de formulario. Puede lograrlo haciendo lo siguiente dentro de los IFRAMEscripts de contenido de:

parent.iframeLoaded();
Aristos
fuente
153
No es compatible con Cross Domain.
Soumya
3
@Soumya El dominio cruzado no tiene nada que ver con este código. Hay un problema de seguridad que se omite con un comando.
Aristos
9
@Soumya Busque para X-FRAME-OPTIONSagregar una línea como: Response.AddHeader("X-FRAME-OPTIONS", "SAMEORIGIN");oresponse.addHeader("X-FRAME-OPTIONS", "Allow-From https://some.othersite.com");
Aristos
15
Esto resuelve el problema de dimensionamiento de iframe de dominio cruzado github.com/davidjbradshaw/iframe-resizer
David Bradshaw
2
@deebs También puedes intentar cambiar iFrameID.height = "";a iFrameID.height = "20px";. La altura predeterminada del iframe del navegador es de 150 px, que es a lo que se ""restablece.
philfreo
112

Una respuesta ligeramente mejorada para Aristos ...

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

Luego declare en su iframe de la siguiente manera:

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

Hay dos mejoras menores:

  1. No necesita obtener el elemento a través de document.getElementById, ya que ya lo tiene en la devolución de llamada de carga.
  2. No es necesario establecer iframe.height = ""si va a reasignarlo en la siguiente declaración. Hacerlo en realidad incurre en una sobrecarga ya que se trata de un elemento DOM.

Editar: si el contenido en el marco siempre está cambiando, llame al:

parent.resizeIframe(this.frameElement); 

desde dentro del iframe después de la actualización. Funciona para el mismo origen.

O para detectar automáticamente:

  // 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);
Pescado azul
fuente
66
¿Qué harías si el contenido del marco siempre cambia?
Kevin
Si el tamaño del contenido sigue cambiando y / o si su iframe está diseñado para ubicarse en otros dominios que no sean el dominio desde el cual el iframe extrae la página, deberá hacer algo diferente.
BlueFish
44
Para esto ... la solución es usar postMessage y recibirMessage. Resolví
BlueFish
La idea es calcular la nueva altura y enviar un mensaje al marco principal que necesita recibir el mensaje y ajustar la altura del iframe en consecuencia.
BlueFish
Siempre fue un corto de píxeles para mí, así que se me ocurrió esto: function resizeIframe(iframe) { var size=iframe.contentWindow.document.body.scrollHeight; var size_new=size+20; iframe.height = size_new + "px"; }
Martin Mühl
56

Descubrí que la respuesta aceptada no era suficiente, ya que X-FRAME-OPTIONS: Allow-From no es compatible con Safari o Chrome . En su lugar, se utilizó un enfoque diferente, que se encuentra en una presentación dada por Ben Vinegar de Disqus. La idea es agregar un detector de eventos a la ventana principal y luego, dentro del iframe, usar window.postMessage para enviar un evento al principal diciéndole que haga algo (cambiar el tamaño del iframe).

Entonces, en el documento principal, agregue un detector de eventos:

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

Y dentro del iframe, escriba una función para publicar el mensaje:

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

Finalmente, dentro del iframe, agregue un onLoad a la etiqueta del cuerpo para activar la función de cambio de tamaño:

<body onLoad="resize();">
Marty Mulligan
fuente
1
Para que esto funcione para mí, tuve que cambiar "window.parent" a solo "parent".
prograhammer
¡Excelente! pero solo carga la altura una vez. Si desea que el iframe sea realmente receptivo, prefiero llamar al método de cambio de tamaño cada segundo, de esta manera:setInterval(resize, 1000);
Jules Colle el
12

Agregue esto al iframe, esto funcionó para mí:

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

Y si usa jQuery intente este código:

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

Hay cuatro propiedades diferentes que puede ver para obtener la altura del contenido en un iFrame.

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

Lamentablemente, todos pueden dar diferentes respuestas y estas son inconsistentes entre los navegadores. Si establece el margen del cuerpo en 0, entonces document.body.offsetHeightda la mejor respuesta. Para obtener el valor correcto, pruebe esta función; que se toma de la biblioteca iframe-resizer que también se encarga de mantener el iFrame del tamaño correcto cuando cambia el contenido o se cambia el tamaño del navegador.

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
fuente
Esto no funciona con elementos que "se acumulan", por ejemplo, tablas de datos o divs flotantes. La altura se basa en la altura normal desenrollada y no en la altura final.
djack109
@ djack109 lo más probable es que algo en su CSS detenga un elemento que se encoge en su página
David Bradshaw
3

Otras respuestas no funcionaban para mí, así que hice algunos cambios. Espero que esto ayude

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

En lugar de usar javscript / jquery, la forma más fácil que encontré es:

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

Aquí 1vh = 1% de la altura de la ventana del navegador. Entonces, el valor teórico de la altura a establecer es 100vh pero prácticamente 98vh hizo la magia.

Binod
fuente
9
Esto no tiene en cuenta la altura del contenido del iframe.
Adrian Pauly
Esto se acerca lo suficiente, cuando usted no tiene una forma sencilla de trabajo alrededor de teatro dominios ...
dsghi
2

Por si acaso esto ayuda a alguien. Me estaba arrancando el pelo tratando de hacer que esto funcionara, luego noté que el iframe tenía una entrada de clase con altura: 100%. Cuando eliminé esto, todo funcionó como se esperaba. Por lo tanto, compruebe si hay conflictos de CSS.

usuario8640976
fuente
2

también puede agregar un requestAnimationFrame repetido a su resizeIframe (por ejemplo, desde la respuesta de @ BlueFish) que siempre se llamaría antes de que el navegador pintara el diseño y podría actualizar la altura del iframe cuando su contenido haya cambiado sus alturas. por ejemplo, formularios de entrada, contenido cargado perezoso, 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)" ...

su devolución de llamada debe ser lo suficientemente rápida como para no tener un gran impacto en su rendimiento general

usuario2520818
fuente
1
Esta es una solución muy ingeniosa que, desde las pruebas iniciales, funciona muy bien. Me interesarían las implicaciones de rendimiento de usar esto.
KFE
Acabo de encontrarme con un caso Uncaught TypeError: Cannot read property 'scrollHeight' of nullya que bodyes null, sin embargo, generalmente funciona.
Caot
1

Estoy usando jQuery y el siguiente código funciona para mí,

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

Encontré que la respuesta de Troya no funcionaba. Este es el mismo código modificado para 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
fuente
0

Para agregar al trozo de ventana que parece estar cortado en la parte inferior, especialmente cuando no tienes desplazamiento, usé:

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

Este es útil cuando necesita una solución sin jquery. En ese caso, intente agregar un contenedor y establecer un relleno en porcentajes

Código de ejemplo HTML:

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

Código de ejemplo CSS:

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

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

La solución simple es medir el ancho y la altura del área de contenido y luego usar esas medidas para calcular el porcentaje de relleno inferior.

En este caso, las medidas son 1680 x 720 px, por lo que el relleno en la parte inferior es 720/1680 = 0,43 * 100, lo que equivale al 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
fuente
0

Una respuesta ligeramente mejorada a 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";
}

Esto toma en consideración la altura de la pantalla de Windows (navegador, teléfono) que es buena para el diseño receptivo y los iframes que tienen una altura enorme. El relleno representa el relleno que desea encima y debajo del iframe en caso de que atraviese toda la pantalla.

Tadej Vengust
fuente
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
fuente
0

Muestra usando PHP htmlspecialchars () + verifica si la altura existe y es> 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
fuente
0

simplemente haga la posición del contenedor de iframe: absoluto e iframe cambiará automáticamente su altura de acuerdo con su contenido

<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
fuente
-1
$(document).height() // - $('body').offset().top

y / o

$(window).height()

Consulte la pregunta sobre desbordamiento de pila Cómo obtener la altura de un elemento del cuerpo .

Pruebe esto para encontrar la altura del cuerpo en jQuery:

if $("body").height()

No tiene valor si Firebug . Quizás ese sea el problema.

Michael L Watson
fuente
Intenté hacer ambas cosas ... todavía sucede en Firefox. Firefox de alguna manera no obtiene window.height () en el iframe. Como mencioné, el script está adjunto al contenido de Iframe y lo llamo en la función document.ready ()
karry