jquery obtiene la altura del contenido de iframe cuando se carga

84

Tengo una página de ayuda, help.php que estoy cargando dentro de un iframe en main.php. ¿Cómo puedo obtener la altura de esta página una vez que se ha cargado en el iframe?

Estoy preguntando esto porque no puedo diseñar la altura de iframe al 100% o automático. Por eso creo que necesito usar javascript ... Estoy usando jQuery

CSS:

body {
    margin: 0;
    padding: 0;
}
.container {
    width: 900px;
    height: 100%;
    margin: 0 auto;
    background: silver;
}
.help-div {
    display: none;
    width: 850px;
    height: 100%;
    position: absolute;
    top: 100px;
    background: orange;
}
#help-frame {
    width: 100%;
    height: auto;
    margin:0;
    padding:0;
}

JS:

$(document).ready(function () {
    $("a.open-help").click(function () {
        $(".help-div").show();
        return false;
    })
})

HTML:

<div class='container'>
    <!-- -->
    <div class='help-div'>
        <p>This is a div with an iframe loading the help page</p>
        <iframe id="help-frame" src="../help.php" width="100%" height="100%" frameborder="1"></iframe>
    </div>  <a class="open-help" href="#">open Help in iFrame</a>

    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
</div>
FFish
fuente
¿El contenido del iFrame proviene del mismo dominio que la página en la que se encuentra?
Andrew
sí lo es Andrew, quiero usar un iFrame porque uso anclas en la página de ayuda
FFish

Respuestas:

102

ok finalmente encontré una buena solución:

$('iframe').load(function() {
    this.style.height =
    this.contentWindow.document.body.offsetHeight + 'px';
});

Debido a que algunos navegadores (Safari y Opera más antiguos) informan que la carga se completó antes de que CSS se procese, debe establecer un tiempo de espera micro y dejar en blanco y reasignar el src del iframe.

$('iframe').load(function() {
    setTimeout(iResize, 50);
    // Safari and Opera need a kick-start.
    var iSource = document.getElementById('your-iframe-id').src;
    document.getElementById('your-iframe-id').src = '';
    document.getElementById('your-iframe-id').src = iSource;
});
function iResize() {
    document.getElementById('your-iframe-id').style.height = 
    document.getElementById('your-iframe-id').contentWindow.document.body.offsetHeight + 'px';
}
FFish
fuente
esta solución funciona muy bien ya que lo anterior solo obtiene el tamaño del contenido de iframes dentro del contenedor mientras que este obtiene el realtamaño
rickyduck
2
Creo que el evento de carga se activa en el mismo bucle de eventos, por lo que un setTimout de 1 milisegundo funcionará igual de bien
George Mauer
hhmmm Cualquiera sabe cómo obtener la altura de un iframe que está oculto en el momento de cargar el padre. Este método devuelve 0.
JT ...
1
Es posible que desee la documentaltura, no la bodyaltura. Usando jQuery puedes agarrarlo con $(this.contentWindow.document).height().
vpiTriumph
Para mayores, es decir, iframe.contentDocument.body.offsetHeight funcionará. stackoverflow.com/questions/2684693/…
user1087079
50

La respuesta menos complicada es usar .contents()para obtener el iframe. Curiosamente, sin embargo, devuelve un valor diferente del que obtengo usando el código en mi respuesta original, debido al relleno en el cuerpo, creo.

$('iframe').contents().height() + 'is the height'

Así es como lo he hecho para la comunicación entre dominios, así que me temo que quizás sea innecesariamente complicado. Primero, pondría jQuery dentro del documento de iFrame; esto consumirá más memoria, pero no debería aumentar el tiempo de carga ya que el script solo necesita cargarse una vez.

Use jQuery de iFrame para medir la altura del cuerpo de su iframe lo antes posible (onDOMReady) y luego configure el hash de la URL a esa altura. Y en el documento principal, agregue un onloadevento a la etiqueta iFrame que buscará la ubicación del iframe y extraerá el valor que necesita. Debido a que onDOMReady siempre ocurrirá antes del evento de carga del documento, puede estar bastante seguro de que el valor se comunicará correctamente sin una condición de carrera que complique las cosas.

En otras palabras:

... en Help.php:

var getDocumentHeight = function() {
    if (location.hash === '') { // EDIT: this should prevent the retriggering of onDOMReady
        location.hash = $('body').height(); 
        // at this point the document address will be something like help.php#1552
    }
};
$(getDocumentHeight);

... y en el documento principal:

var getIFrameHeight = function() {
    var iFrame = $('iframe')[0]; // this will return the DOM element
    var strHash = iFrame.contentDocument.location.hash;
    alert(strHash); // will return something like '#1552'
};
$('iframe').bind('load', getIFrameHeight );
Andrés
fuente
Hola Andrew hasta ahora muy buena ayuda aquí. content () funciona muy bien, pero todavía necesito probarlo con un regulador de ancho de banda. Tal vez puedas usar la propiedad innerHeight (). Tengo un problema en FF (OSX) al usar su solución poniendo la altura en el hash. ¿FF parece seguir cargando la función getDocumentHeight () en un bucle infinitivo? Safari está bien ..
FFish
Interesante. Agregué una verificación que evita la configuración del hash si ya hay un valor allí. Es posible que deba modificar esto si está cargando Help.php con un valor hash (por ejemplo <iframe src="../Help.php#introduction" />)
Andrew
Por cierto, suponiendo que pueda ajustar la diferencia de altura, probablemente no necesite usar el hash para comunicarse fuera del iframe. Si usa el método hash, poner un sleep(5)en su Help.php también debería ser una buena forma de probar cualquier condición de carrera. Si el iframe se dispara de alguna manera onLoadantes onDOMReady, debería aparecer aquí.
Andrew
23

Encontré que lo siguiente funciona en Chrome, Firefox e IE11:

$('iframe').load(function () {
    $('iframe').height($('iframe').contents().height());
});

Cuando el contenido de Iframes termine de cargarse, el evento se activará y establecerá la altura de IFrames a la de su contenido. Esto solo funcionará para páginas dentro del mismo dominio que el del IFrame.

Jack Zach Tibbles
fuente
funciona bien, pero para el ancho tengo que hacerlo así o el contenido se corta $ ('iframe'). width ($ ('iframe'). contents (). width () + 30);
Geomorillo
@AminGhaderi funciona bien para mí en Firefox 40.0.3
mixkat
@mixkat, cargo un sitio web en iframe a través de esta solución y todas las soluciones en este tema, ¡pero para mí no funciona! Creo que estas soluciones funcionan para una página y no funcionan cuando cargamos un sitio web completo en el iframe. mi ingles es muy malo, espero que lo entiendas.
Amin Ghaderi
@AminGhaderi, si lo entendí bien, espera que esto funcione para todas las páginas de su sitio, pero por supuesto, esto no funcionará para todas las páginas, ya que solo se ejecuta una vez cuando carga el marco. Entonces, funcionará bien para la primera página, pero luego, si desea que funcione para páginas más largas, tendrá que hacerlo nuevamente, ya sea cargando el marco nuevamente con la nueva página o llamando al contenido.height en algún otro punto en su flujo
mixkat
9

El código para hacer esto sin jQuery es trivial hoy en día:

const frame = document.querySelector('iframe')
function syncHeight() {
  this.style.height = `${this.contentWindow.document.body.offsetHeight}px`
}
frame.addEventListener('load', syncHeight)

Para desenganchar el evento:

frame.removeEventListener('load', syncHeight)
cchamberlain
fuente
3
¡Agradable y sencillo! Desafortunadamente, no funciona para iframes entre dominios :(
TimoSolo
3
Sí, no tuve suerte. Aprovecharía la biblioteca iframe-resizer para eso. Por supuesto, debe tener el control de ambos dominios para que funcione.
cchamberlain
6

No necesita jquery dentro del iframe para hacer esto, pero lo uso porque el código es mucho más simple ...

Pon esto en el documento dentro de tu iframe.

$(document).ready(function() {
  parent.set_size(this.body.offsetHeight + 5 + "px");  
});

agregó cinco arriba para eliminar la barra de desplazamiento en ventanas pequeñas, nunca es perfecto en tamaño.

Y esto dentro de su documento principal.

function set_size(ht)
{
$("#iframeId").css('height',ht);
}
RkaneKnight
fuente
Esto tampoco funcionará si está mostrando un PDF dentro del iframe.
Jason Foglia
Lo siento, pero su ejemplo "dentro del marco" está claramente basado en jQuery.
T-moty
4

esta es la respuesta correcta que funcionó para mí

$(document).ready(function () {
        function resizeIframe() {
            if ($('iframe').contents().find('html').height() > 100) {
                $('iframe').height(($('iframe').contents().find('html').height()) + 'px')
            } else {
                setTimeout(function (e) {
                    resizeIframe();
                }, 50);
            }
        }
        resizeIframe();
    });
Javier Gordo
fuente
4

Una línea simple comienza con una altura mínima predeterminada y aumenta hasta el tamaño del contenido.

<iframe src="http://url.html" onload='javascript:(function(o){o.style.height=o.contentWindow.document.body.scrollHeight+"px";}(this));' style="height:200px;width:100%;border:none;overflow:hidden;"></iframe>

Pixelomo
fuente
1

Esta es una solución gratuita de jQuery que puede funcionar con SPA dentro del iframe

document.getElementById('iframe-id').addEventListener('load', function () {
  let that = this;
  setTimeout(function () {
    that.style.height = that.contentWindow.document.body.offsetHeight + 'px';
  }, 2000) // if you're having SPA framework (angularjs for example) inside the iframe, some delay is needed for the content to populate
});
Envil
fuente
1

Esta es mi versión no-jquery amigable de ES6

document.querySelector('iframe').addEventListener('load', function() {
    const iframeBody = this.contentWindow.document.body;
    const height = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight);
    this.style.height = `${height}px`;
});
César Rivera
fuente