El no efecto FOUC

Publicado en Optimización web( WPO ) hace 3 años y 5 meses. Leído 2579 veces.

Esta semana seguiré con la optimización de páginas webs y más concretamente con el efecto FOUC.

Procedimiento de carga actual de páginas webs.

Como me imagino que sabrás, el proceso de carga de una página web es el siguiente:

  1. Los navegadores piden el HTML al servidor que tiene una IP determinada( obtenida basada en un dominio ).
  2. Conforme llega el HTML de la página web, el navegador lo va procesando y si encuentra enlaces de recursos(imágenes, Javascript, CSS), los va pidiendo al servidor como hiciera con el HTML.
  3. Una vez que ya tenga todos los recursos bajados, excepto si hablamos de javascript deferidos o asincrónicos, empieza a mostrar la página con los estilos de tu CSS.

Es decir, que entre el paso dos y tres, el navegador se queda a la espera de todos los recursos. Vamos a tratar de exagerar el proceso para que se compruebe que esto es así. Para ello, crea un archivo .htaccess en tu directorio de archivos CSS con el siguiente contenido:

# Permite incrustar código PHP
# dentro de un archivo CSS
AddType application/x-httpd-php .css

Esto, como sus comentarios indica, es para ejecutar código PHP dentro de tus archivos CSS. No te asustes, luego lo borras.

Ahora, añade el siguiente código en la parte superior de tu archivo CSS principal( ej: main.css ), debajo deben quedar los estilos:

sleep(20);
?>

/* Debajo de este comentario tu código CSS */

Con esto conseguimos que tu código CSS tarde en descargarse 20 segundos desde la petición del navegador. Si ahora recargas tu página, verás que demorará al menos 20 segundos en mostrarse tu página web. Tu HTML se cargó anteriormente, pero el navegador no hace nada hasta que no tiene todo. Usando Firebug y pestaña "Red" lo verás más claro.

Nota: Antes de proseguir recuerda borrar el htaccess que creaste y quitar el código PHP que añadiste al archivo principal de CSS.

Motivo y definición.

Otra manera más óptima de hacer esto es que el navegador cargara tu página web con los estilos por defectos y posteriormente, cuando estuvieran los archivos CSS bajados, aplicar los estilos de ellos. Esto es lo que se hacía antiguamente, pero creaba un desagradable efecto llamado FOUC. Más claramente, FOUC era el cambio que se producía en tu página web cuando pasaba de tener los estilos predefinidos del navegador a los estilos definidos por ti. Como era muy desagradable y producía problemas con javascript, decidió cambiarse el proceso a como lo conocemos actualmente.

Consecuencias.

Las consecuencias están muy claras y muy obvias: * Un número elevado de archivos CSS o Javascripts hará que tu página tarde en aparecer. * Una alta latencia en tu servidor hará que todo se retrase enormemente. * Un archivo CSS o un JS muy pesado bloqueará la página hasta su descarga.

Recomendaciones.

  • Si tienes un archivo CSS muy pesado, puedes pasar algunos de los estilos más comunes al HEAD de tu HTML. Así bajará el peso de tu CSS y se verá tu página web antes. A mi no me gusta esta opción, pero la comento porque es una de las más utilizadas e, incluso, la recomienda Google.
  • Distribuye tu CSS o JS entre varios archivos y que cada uno de estos archivos se cargue sólo en la página web que lo necesite.
  • Lo contrario del punto anterior es que si usas muchos archivos CSS comunes a todas tus páginas, lo mejor es unificar dichos archivos en uno solo. Así te afectará menos la latencia de tu servidor. Lo mismo se puede aplicar a Javascript.
  • Si minimizas tus archivos CSS y JS, estos pesarán menos y descargarán antes.
  • Recomiendo no usar jQuery o Bootstrap. En otro post profundizaré en ello.
  • Como siempre una web minimalista es lo más adecuado y lo recomendable si quiere una mejor experiencia para tus visitantes. Finalmente, os deseo a todos unas felices fiestas y un prospero año nuevo.

4 comentarios

Hola Manolo

Sólo por perfilar y arreglar fallos de sintaxis en el post, el nombre es FOUC (Flash Of Unstyled Content, y no FUOC como tu estás poniendo, que seguro que ha sido un lapsus jejeje) que es el intervalo de tiempo en el que una web muestra unos estilos (o estilos por defecto como tú has expuesto) mientras se cargan otros.

Esto también pasa en las webs desarrolladas con AngularJS cuando se utiliza para el binding la sintaxis de doble llaves {{ }} (double courly braces) en vez de la directiva de binding ng-bind (o ng-model).

Yo intento evitar esa sintaxis en la medida de lo posible, aunque a veces por evitar eso acabas creando más componentes HTML innecesarios. Cómo siempre, depende de la página y/o aplicación.

Escrito por Antonio David Perez Morales el 24-12-2014 a las 09:22

Hola, Tico,

En el anterior me pasó con el DNT que pusé DT :S. Cada vez estoy más empanado :S. Gracias por el aviso. A ver si los próximos los hago con más tiempo y también incluyo los ejemplos en github.

Respecto a lo que comentas. Sí, el FOUC, tal como viene definido en la Wikipedia, también es común hoy en día con Javascript, por ejemplo, en AngularJs( que no conozco y por tanto, no sabía que pasaba ) pero también con jQuery y sus derivados( Ember/Backbone/etc).

Sin embargo, para el caso estos de Javascript, yo no los considero FOUC como hace la Wikipedia, porque ya estilo tiene, lo único es que normalmente cambia la estructura de html y, por tanto, ya no encajaría con la U de Unstyled. Quizás para angular si es un unstyled, no lo sé, como digo no lo conozco.

Gracias por el buen aporte, Tico y por pasar por aquí. Felices fiestas.

Estoy de acuerdo en que ya no es tanto “unstyled”. En el caso de angular es debido al ciclo de digest donde se renderizan de nuevo los bindings que hayan sido modificados. Puedes usar variables de tu ámbito que actuan como estilos y clases, de ahi que se produzca un poco de FOUC.

En el caso que dije del double curly braces, AngularJS parsea el DOM para procesar la sintaxis de binding de {{}}, y durante ese tiempo tú estarás viendo {{variable}}, y no el resultado de evaluar variable, que se realiza posteriormente en cada ciclo de digest de Angular ( concretamente añade un watch para evitar tener que procesar todo el DOM en cada ciclo y solo reevaluar lo que está siendo “vigilado”). No es FOUC en sí, pero es el mismo concepto.

Por eso, si usas la directiva ng-bind, al especificar la variable del scope a bindear como atributo del elemento, dicho elemento se vería vacío (o con un valor por defecto que especifiques en el scope) y en el siguiente ciclo de digest de Angular, ya se vería dicha variable evaluada como valor de ese elemento.

No he usado Ember por ejemplo, pero seguro que el concepto y el problema que lo produce es similar.

Saludos

Escrito por Antonio David Perez Morales el 24-12-2014 a las 10:57

Feliz año nuevo, Tico y gracias por tu aportación.

Siento no haberte podido moderar antes tu comentario, pero he estado de vacaciones y desde el móvil era imposible acceder al WordPress.

Un saludo

Tenía pensado que los recursos enlazados cuando son imágenes ( es decir, el elemento ) no bloqueaban el procesamiento de la página. Eso sí hay que tener cuidado con el número máximo de conexiones físicas ( por dominio ) que soportan los navegadores . En teoría son 2

Por eso , cuando las imágenes son muy grandes , se ve van apareciendo poco a poco ( o incluso de golpe ) tras estar ya renderizada la página.

El evento onReady ocurriría cuando ha terminado de interpretarse la página pero pueden faltar imágenes El evento onLoad ocurre cuando todos los recursos solicitados han sido obtenidos y visualizados.

Otra cosa importante es que los creados en el DOM dinámicamente requieren el recursos asincronamente pero se procesan en el orden añadido en el DOM ( independientemente de cual termine antes en obtener el recurso ). Hay una excepcion en esto ultimo en IE y se requiere crear el elemento con defer.

Con los CSS no se si ocurre igual.

Escrito por jmzc el 05-01-2015 a las 19:12

jmzc, gracias por comentar, te respondo por partes:

– Los navegadores usan hilos/threads para bajar los recursos. Si los hilos están ocupados bajando imágenes puede que retrasen la descarga de CSS y JS. De ahí, que para cuando haya muchas imágenes sea recomendable usar técnicas como lazy load. Otra opción, es que las imágenes sean parte del CSS( por ejemplo, fondos, botones, bullets, … ), en este caso, al navegador no le queda otra que esperar. Aunque, en este caso, no esperará hasta tener todo de todo para ir mostrando los estilos, los irá mostrando poco a poco conforme los interpreta. Si no estamos ni en el primer caso ni el segundo, es decir, tenemos pocas imágenes de manera enlazada. Lo que ocurrirá es lo que comentas, sin embargo, hay que tener cuidado porque si no hemos especificados ni width ni height para las imágenes puede provocar que nuestra página tenga una desmaquetación ( leve o aguda dependiendo de cada diseño ) hasta que las imágenes lleguen. Pues es entonces, cuando el navegador calcularía el tamaño de las imágenes. Por ello, es recomendable poner un width y un height a las imágenes

– Respecto a javascript, pasa como con CSS si está puesto en el HEAD y sin defer/async. Es decir, No mostrará nada de la página hasta que se haya bajado e interpretado todo el javascript. Si lo ponemos como async estaremos ocupando hilos de ejecución. Es decir, que si estamos usando hilos para bajar javascript y estos van lentos, se retrasará la carga general de la página y veremos que todo va a trompicones. Si lo ponemos como defer, la descarga se retrasará hasta el final, aún así y por experiencia seguirá bloqueando la descarga de imágenes o al revés ( las imágenes retrasarán la carga del javascript ).

Por todo lo dicho, tendrías que tener cuidado en el evento onReady y asegurarte que ya están todas las imágenes. Puede que tengas suerte y el navegador las tenga cacheada y no haya problema. Pero, si no las tiene en caché y se retrasaron por bloqueo de javascript, te dará error.

– Respecto al CSS, básicamente es lo que dice el post: El navegador no mostrará nada de nada hasta que no tenga todos los CSS bajados. Eso es lo que básicamente explica el post.

Como veo que esto no está del todo claro, trataré para finales de esta semana hacer un post sobre ello. Incluiré ejemplo de manera que se pueda ver las distintas opciones.

Un saludo

Gracias

No me queda claro el comentario “Otra opción, es que las imágenes sean parte del CSS( por ejemplo, fondos, botones, bullets, … ), en este caso, al navegador no le queda otra que esperar. Aunque, en este caso, no esperará hasta tener todo de todo para ir mostrando los estilos, los irá mostrando poco a poco conforme los interpreta.”

Realmente tengo dudas sobre en qué momento el navegador empieza a pintar Me esperaré a tu post

Un saludo

Escrito por jmzc el 05-01-2015 a las 20:54

Deja un comentario

Puedes usar Markdown para formatear tu comentario.

Este sitio utiliza cookies propias y de terceros para mejorar tu experiencia con el sitio web. Al continuar con la navegación consideramos que acepta su uso.