jueves, 23 de febrero de 2012

Ajustar el tamaño de un IFrame a su contenido

O cómo evitar que aparezcan scrolls repetidos en una aplicación web.
En relación con la entrada “Cómo acceder a una aplicación ASP.NET externa desde Sharepoint” apareció un problema con el visor de páginas (más bien con el IFrame utilizado para exponer la aplicación en Sharepoint) relacionado con las dimensiones del mismo.
En concreto, lo que sucede es que si la página que “asomamos” por el IFrame es más grande que la altura que le hemos asignado al IFrame, aparece una barra de scroll dentro del IFrame. Esto ya de por sí queda un pelín ‘raro’, pero si lo combinamos con que en la página ‘contenedora’ también aparece el scroll, entonces ya queda fatal de la muerte, con dos scrolls “independientes”
NOTA: Lo lamento enormemente, pero en esta ocasión no dispongo de ninguna de captura de pantalla, así que toca todo texto ‘plano’

Solución 1

La más rápida y sencilla, poner al IFrame una altura ‘suficiente’ para que no aparezca el scroll interior. ¿Hay alguien a quien se le ocurra el problema con esta solución?
¿no?
Venga, que es muy fácil: El problema es que si ponemos la altura muy grande (porque sabemos o intuimos que el contenido del IFrame es también grande, lo que conseguimos es que en la página ‘contenedora’ aparezca el scroll vertical… Pero siempre! Imaginad que una de las páginas que asomamos por el IFrame es más pequeña, entonces queda un scroll en la pantalla, pero todo vacío hacia abajo, de verdad no queda muy bien.

Solución 2

[CORRECCIÓN]] Ojo porque el código original publicado puede llevar a un problema de uso de CPU en el equipo cliente. Las correcciones necesarias aparecen en rojo en el código.

¿No estaría bien que el IFrame que utilizamos se ajustase a su contenido? Como podéis imaginar por el título del artículo, esto es precisamente lo que se va a explicar a continuación, y además es bastante sencillo.
NOTA: Una cosa a tener en cuenta. Esta solución se implementa con JavaScript y accede al contenido del IFrame, tenéis que tener en cuenta que si el contenido está en un dominio diferente al de la página contenedora, encontraréis problemas de “Acceso Denegado” salvo que implementéis las instrucciones del artículo mencionado al principio.

Al turrón (para la Solución 2)

En la página donde vamos a poner el IFrame (o mejor aún en un archivo .js) ponemos el código de JavaScript que tenemos a continuación. El archivo .js está disponible para descarga desde aquí.

<script type="text/javascript" language = "javascript" >
    function doIframe(){
        o = document.getElementsByTagName("iframe");
        for(i=0;i<o.length;i++){
            if (/\bautoHeight\b/.test(o[i].className)){
                removeEvent(o[i],'load', doIframe);
                setHeight(o[i]);
                addEvent(o[i],"load", doIframe);
            }
        }
    }
    function setHeight(e){
        if(e.contentDocument){
            e.height = e.contentDocument.body.offsetHeight + 35;
        } else {
            e.height = e.contentWindow.document.body.scrollHeight;
        }
    }
    function addEvent(obj, evType, fn){           
        if(obj.addEventListener)
        {
            obj.addEventListener(evType, fn,false);
            return true;
        } else if (obj.attachEvent){
            var r = obj.attachEvent("on"+evType, fn);
            return r;
        } else {
            return false;
        }
    }
    function removeEvent(obj, evType, fn){
        if(obj.removeEventListener)
        {
            obj.removeEventListener(evType, fn,false);
            return true;
         } else if (obj.detachEvent){
             var r = obj.detachEvent(""on""+evType, fn);
             return r;
         } else {
             return false;
         }
     }
</script>

No voy a entrar en qué hacen las funciones setHeight (creo que es obvio) y addEvent (para ésta, está Google) pero sí que me voy a detener un poco en la función doIframe, ya que es fundamental para el funcionamiento del script. Como podemos ver, esta función se recorre todos los IFrames que existan en la página, y les adjunta el evento “load”, pero solamente a aquellos IFrames que tengan especificada una estilo CSS “autoHeight”. ¿Por qué? Si no ponemos esa condición o similar, el script se ejecutará para todos los IFrames que tenemos en la página, y eso puede producir una sensación de descontrol, es preferible elegir cuáles de los IFrames queremos que se ajusten y cuáles no es necesario.
Con esto no hemos terminado, necesitamos el código de JavaScript que desencadena todo el proceso, se puede incluir en la página o en el mismo archivo .js:

<script type ="text/javascript" language ="javascript" >
    if (document.getElementById && document.createTextNode){
        addEvent(window,'load', doIframe);
    }
</script>

Estas instrucciones son las que consiguen que el proceso se lance al cargar la página en el navegador.
Y ya para terminar un detalle del IFrame, para recordar la condición del estilo css:

<iframe id = "xxx" frameborder = "0" scrolling = "no" runat ="server" class = "IframeCarga autoHeight" visible = "false" src = "/dirección" ></iframe>
Y esto es todo!!!!

3 comentarios:

Unknown dijo...

Gracias!!

es la idea que buscaba

saludos!!

Fran dijo...

OJO. La entrada original tenía un problema con Internet Explorer que podía provocar un uso excesivo de CPU, por favor revisar el nuevo código tanto en la entrada como en el comprimido adjunto.

producciones.uy dijo...

Muchas gracias, me fue de muchísima utilidad.
En la definición del iframe le agregué el atributo del width para que no quedara cortado:
iframe id="nombre" frameborder="0" scrolling="no" class="IframeCarga autoHeight" runat="server" src="/direccion" width="100%"

Pueden ver cómo me quedó en: www.quejese.com.uy/FAQ.aspx