Conoce cómo funciona el browser y optimiza tu código frontend

26/Nov/2014 40

Hace no más de 2 años que la tendencia de los usuarios de internet han visto cómo han crecido de manera indirecta las siguientes afirmaciones:

  • Los sitios han crecido en peso de sus archivos (CSS, JS, imágenes, tipografías).
  • La cantidad de usuarios que utilizan redes móviles (2G, 3G y 4G) ha crecido mucho, pero muuuucho.

Por ende:

Hay poca consciencia de que sitios pesados y redes móviles limitadas no son buenos coeficientes de una misma ecuación.

Esto debe llevarnos a una nueva manera de pensar sobre la optimización de sitios relativos al front-end. Y no sólo por los usuarios y las experiencias que puedan llevar un lento desempeño de tus sitios en sus dispositivos; recuerda que Google considera dentro de su algoritmo de posicionamiento que el tiempo de renderizado sea menor a 1 segundo, suponiendo que con 3 segundos el usuario ya se fue de tu sitio y esperando 10 segundos lo más probable es que nunca más vuelva.

En este artículo mostraré cómo funciona un browser desde que inicia el render del código de una página y con esa información algunas técnicas para aumentar la optimización de los elementos que la componen.

Tramo crítico de renderizado

Por años se consideró como velocidad de carga como la rapidez en que vemos la estructura, diseño y contenido de la página cargada. Pero luego Google definió el tramo crítico de renderizado (critical rendering path) como la secuencia de pasos que el browser toma de convertir código y recursos asociados en la vista inicial de una página web. Esto cambia la noción completamente, orientándola hacia lo esencial, lo fundamental en tu esa página para después cargar lo secundario. ¿El foco? Contenido más rápido, mayor pagerank.

A continuación mostraré los procesos que suceden cuando ingresas una URL en el browser y el servidor resuelve lo que esa URL contiene:

De nada a contenido

Básicamente lo primero que entregará un servidor será código HTML como el siguiente:

<!DOCTYPE html>
<html lang="es">
  <head>
    <title>Título</title>
    <link href="style.css" rel="stylesheet">
  </head>
  <body>
      <p>Texto <b>en negrita</b>.
      <img src="imagen.jpg">
    </p>
  </body>
</html>

Lo que hace el navegador es parsear este código dentro del DOM (Document Object Model), el que corresponde a la representación en forma de árbol del lenguaje HTML. El browser construye el DOM incrementalmente, o sea, comienza a parsear el HTML apenas el primer trozo de código es recibido y agrega nodos a la estructura del árbol tanto como sea necesario:

img1

En este punto la ventana del navegador aún no muestra nada, pero se está referenciando a un archivo style.css dentro de <head /> Nótese que los estilos de un sitio son parte crítica del renderizado dado que tienen que ser descargados apenas el parser HTML pase por <link />. Si tenemos definido como estilos básicos:

p { font-weight: normal; }
p b { display: none; }

Éstos son parseados dentro de CSSOM ó CSS Object Model, el que desafortunadamente no puede ser construido incrementalmente como el DOM debido al efecto cascada que determina la naturaleza de CSS; imagina que después de la declaración CSS anterior definieras:

p { font-weight: bold; }

Lo que causaría que sobre-escribieras la primera declaración de p {}, demostrando que se debe esperar que todo el CSS sea descargado y procesado antes podamos renderizarlo. Por ende, CSS bloquea el render hasta que la representación de CSS y HTML sean entendidos por el browser, construyendo recién en ese momento el árbol de renderizado (render tree). Esta estructura combina el DOM y CSSOM pero considerando sólo los elementos visibles:

img2

Como habrán notado, el <b> dentro de <p> no está considerado debido a que no es visible para el DOM (display: none;) mediante CSS.

Los pixeles recién aparecen luego de 2 pasos: estructura (layout) y pintura (paint). La estructura se encarga de calcular las posiciones y dimensiones de cada elemento respecto al viewport actual; ya la pintura agrega los colores, formas, sombras y demás efectos de estilo terminando de mostrar la página renderizada. Cada vez que el árbol de render cambia (por ej. mediante JavaScript) o el viewport cambia (utilizando interfaces líquidas, adaptativas ó responsive) estructura y pintado vuelven a crearse.

Estructuras líquidos/responsive tienen mayor carga en el layout/paint que estructuras adaptativas

El tramo crítico de renderizado completo se ve en el siguiente diagrama:

img3

¿Y las imágenes?

No son considerados críticas para la construcción del DOM, por lo tanto, no bloquean el renderizado de una página. Pero sí influyen y bloquean el evento Load, el que corresponde a la carga y proceso de todos los elementos considerados dentro de un HTML adicionando CSS y JavaScript. Así vemos que las imágenes deben ser siempre optimizadas pero no bloquean el tramo crítico de renderizado.

No olvidemos a JavaScript

JavaScript es otro actor que influye directamente en nuestro tramo crítico de renderizado. A partir del primer código HTML entregado, lo expandiremos agregando JavaScript:

<!DOCTYPE html>
<html lang="es">
  <head>
    <title>Título</title>
    <link href="style.css" rel="stylesheet">
  </head>
  <body>
      <p>Texto <b>en negrita</b>.
      <script>
      document.write('<h1>olakease</h1>');
      var elem = document.querySelector('h1');
      elem.style.color = 'green';
	    </script>  
      <img src="imagen.jpg">
    </p>
  </body>
</html>

Este sencillo script demuestra que cambiar el DOM puede tambien influir en el CSSOM. Mientras JavaScript agrega un nuevo elemento al DOM <h1>olakease</h1>, el parser debe parar hasta que el script sea ejecutado por completo. Luego se determina el color del elemento recién creado, lo que hace que CSSOM esté presente antes de que el script sea ejecutado.

Ahora aislemos el script llevándolo a un llamado de un archivo externo .js:

<!DOCTYPE html>
<html lang="es">
  <head>
    <title>Título</title>
    <link href="style.css" rel="stylesheet">
  </head>
  <body>
      <p>Texto <b>en negrita</b>.
      <script src="app.js"></script>  
      <img src="imagen.jpg">
    </p>
  </body>
</html>

img4

El nuevo archivo externo realiza un request adicional, pero a pesar del lugar en que lo llames dentro del HTML, siempre CSS será parseado primero. Apenas CSSOM es interpretado, el contenido del script puede ser ejecutado y solo después de esto el parser del DOM puede terminar de ser ejecutado. Es un juego de parser-render-bloqueo-render-bloqueo-parser.

Quitémosle peso innecesario al browser

Técnicas de optimización

Ahora que conocemos los conceptos, es hora de anotar cómo podemos poner algo en práctica. Hay 3 puntos claves donde puedes optimizar el tramo crítico de renderizado y que permite que el browser produzca resultados visibles con mayor rapidez.

No olvides tener en cuenta que debes utilizar estos consejos con cautela y sabiduría; hazlo con cuidado, asesórate y recuerda que no existen recetas milagrosas ni fórmulas de éxito; cada situación es particular.

Minimiza los bytes que son llamados por el servidor

Regla simple: mientras más liviano tu sitio, más rápido carga y renderiza. Sencillo. Minifica, comprime y utiliza caché en tus assets estáticos y tu HTML. No temas comprimir el código HTML removiendo espacios blancos (whitespaces) y comentarios innecesarios cuando vayas a ambiente productivo.

Minimiza el CSS que bloquea el renderizado

Recuerda que CSS bloquea al renderizado y ejecución de JavaScript, así que entregar los estilos al usuario lo más rápido posible es imperativo. Asegúrate que todas las etiquetas <link> estén dentro del <head> de tu documento HTML para que el navegador las cargue y renderice de inmediato.

Otra estrategia es disminuir el CSS que bloquea el renderizado mediante media queries. Digamos que nuestro sitio de ejemplo tiene estilos para impresión y reglas declaradas para dispositivos móviles en orientación landscape. Puedes separar el CSS en varios archivos y dejar que el browser las parsee condicionalmente:

<head>
  <title>Sitio Ejemplo</title>
  <link href="style.css" rel="stylesheet">
  <link href="print.css" rel="stylesheet" media="print">
  <link href="landscape.css" rel="stylesheet" media="orientation:landscape">
</head>

Claramente el peso de nuestro style.css será menor debido al código removido y que repartimos entre los otros 2 archivos .css, los cuales serán utilizados sólo cuando realmente necesarios. Esto no quiere decir que no serán cargados; el navegador los descarga al inicio pero en menor prioridad que el principal y en paralelo al proceso de renderizado.

Otro recurso es agregar como estilo inline (dentro del <head> mediante <style></style>) evitando que el browser realice un request al servidor por un nuevo archivo. Esta técnica se utiliza para el primer render, el que se realiza above de fold. El CSS que comanda lo que primero está en el viewport del browser, para luego continuar con el resto de la estructura mediante archivos enlazados con <link>.

<head>
  <title>Sitio Ejemplo</title>
  <script>
  header { ... }
  header nav { ... }
  header .logo { ... }
  </script>
  <link href="style.css" rel="stylesheet">
</head>

Algunas herramientas que te ayudan a calcular el CSS crítico (above the fold) y separar los estilos para servir esta vista son:

Finalmente, ¿que tal llamar tus archivos .css de forma asíncrona? Suena descabellado pero se creó loadCSS, una función JavaScript que carga CSS de forma asíncrona, especial para esos pesados @font-face por ejemplo.

Minimiza el bloqueo del parser de JavaScript

Lo misma regla ocurre con JavaScript. Si necesitas unas pocas líneas de código en el render inicial, considera agregarlos dentro de tu HTML mediante <script></script> ahorrarás descargas al servidor y por ende tendrás una respuesta más rápida al usuario.

En un caso óptimo llamas todo tu JavaScript en un mismo archivo al final de tu documento HTML. Pero en otros pasos, escribiendo código modular, puedes separar tus archivos y llamarlos asincrónicamente siempre y cuando no interactúen con el DOM ni el CSSOM:

...
    <script src="retardo.js" async></script>
  </body>
</html>

Con esto le dices al navegador que no necesita ejecutar el script en el momento en que es llamado en documento HTML. Esto también permite que el browser continúe construyendo el DOM y ejecute scripts cuando el DOM esté completo. Imagina código de Analytics, redes sociales en este retardo.js, el que no interactúa con el DOM ni el CSSOM.

Finalmente, una técnica y herramienta interesante es basket.js donde en teoría, cargas tus script críticos y recurrentes y los guardas en el localstorage del browser (HTML5), para utilizarlo desde ahí mientras dure la navegación del usuario y cuando éste regrese.

Suena bien. Manos a la obra.

Links:

Comentarios

  1. nikoskip [#]

    Lo de basket.js está muy bueno, no lo conocía, gracias por compartir.

    Pienso que hay que tener ojo cuando se trabaja en sitios mobile respecto a cargar cosas ‘async’. En redes móviles la latencia es tremenda, de acuerdo a lo que he leído e investigado es mucho mejor intentar concatenar y minifcar nuestros assets, a cargarlos de manera asíncrona… bueno, siempre depende del caso. Al respecto, es muy interesante esta charla: https://www.youtube.com/watch?v=7gtf47D_bu0

    Saludos.

    • Jaime [#]

      Muy buen post Jorge.

      Sólo agregar que también se debe tener cuenta el rendimiento del sitio una vez ya cargado y renderizado.
      ¿como es eso? el proceso de renderizado se divide en fases como lo explicas en el articulo, estás fases son
      layout, painting y composite. El renderizado no se hace sólo una vez, se hace cada vez que algún elemento dentro del árbol DOM cambie su posición o forma, como? modificando sus propiedades CSS.
      Hay propiedades CSS que gatillan estas 3 fases, otras 2 y otras ninguna. Algunas desencadenan las 3 fases al cambiar su valor por defecto, pero sólo 2 o ninguna cuando actualizamos su valor.

      Por ejemplo, la propiedad height gatilla layout, paint y composite. Tanto cuando cambiamos su valor por defecto, como cuando actualizamos un valor previamente establecido por uno mismo. Height hace cambiar la geometría del elemento, esto puede hacer cambiar la posición y dimensiones de otros elementos en la pantalla por ende el browser debe hacer operaciones de layout nuevamente.
      Al recalcular estructura y dimensiones (layout) , se deben volver a realizar operaciones de pintado (painting) (porque cambiaron dimensiones) esto hace que también se desencadene composite. composite básicamente es juntar todas las layers y texturas pintadas por separado, dibujarlas en el orden que corresponda y convertirlas en una sola «imágen»: la página renderizada.

      es muy común realizar muchos cambios de propiedades a elementos cuando el puntero se pasa por encima de un elemento (:hover),
      este es uno de los principales puntos por donde se degrada la experiencia de uso. Aplicar muchos cambios CSS para crear determinados efectos, exige trabajo constante al browser re calculando estructura, re pintando y re componiendo la página, haciendo que veamos el sitio «lento» por ejemplo al hacer scroll, al observar que ciertas animaciones o transformaciones no se ven como esperamos o no «se cortan», etc etc.

      es un laaargo tema pero dejo un link donde hay una lista con algunas propiedades CSS y que tan «caras» en coste de rendimiento son cada una:
      http://csstriggers.com/

      Saludos y ojala tenga segunda parte este post 😀

      • Jaime [#]

        me auto corrijo en el primer parrafo, redacté mal:
        «»Hay propiedades CSS que gatillan estas 3 fases, otras 2 y otras ninguna»»
        por
        «»Hay propiedades CSS que gatillan estas 3 fases, otras 2 y otras solo una»»

      • Jorge Epuñan [#]

        Gracias por tu excelente aporte Jaime, en este artículo quise enfocarme en la performance desde el server hacia el browser; lo q mencionas se enfoca del browser hacia el usuario, lo q da para otro artículo.

        Abrazos.

  2. Ezgi [#]

    Good job, thanks for sharing.

  3. >: ( [#]

    «Aplicar muchos cambios CSS para crear determinados efectos, exige trabajo constante al browser re calculando estructura, re pintando y re componiendo la página, haciendo que veamos el sitio “lento” por ejemplo al hacer scroll, al observar que ciertas animaciones o transformaciones no se ven como esperamos o no “se cortan”, etc etc.»

    Que es lo que le pasa a este sitio web. Muy bonito, muchos estilos, pero se ha abusado tanto de ellos que va lento a mas no poder (la página principal es horrorosa de lo mal que va) y carga muy muy lenta. Carga tan lento que pensaba que no había contenido.

    • Jorge Epuñan [#]

      ¯\_(ツ)_/¯ no se puede agradar a todos, muchos halagos y este es la primera queja. Enfin, gracias por tus palabras.

      • Amado [#]

        No creo que el comentario se haya hecho con mala intención, la web es muy bonita y atractiva sin embargo si va algo lenta con los estilos y animaciones, aún así tu artículo es muy bueno y me ayudo a comprender varias cosas. Te mando un saludo, felicitaciones y gracias.

  4. Zarabianieprzezinternet [#]

    I enjoy what you guys tend to be up too. This
    kind of clever work and exposure! Keep up the amazing works guys
    I’ve added you guys to my personal blogroll.

  5. zarabianie [#]

    Hi there, I enjoy reading all of your article. I wanted to
    write a little comment to support you.

  6. Cua hang may tinh PC [#]

    Hello very cool web site!! Man .. Beautiful .. Wonderful ..
    I will bookmark your site and take the feeds also? I am happy to find
    a lot of helpful information right here in the submit, we’d
    like develop extra strategies on this regard, thank you for sharing.

    . . . . .

  7. shemale movies [#]

    It’s really a cool and useful piece of info. I’m happy that you shared this helpful info with us. Please stay us informed like this. Thanks for sharing.

  8. xxx [#]

    We stumbled over here coming from a different page and thought I might as
    well check things out. I like what I see
    so now i am following you. Look forward to looking into your web page for
    a second time.

  9. Reddit.com [#]

    excellent post, very informative. I ponder why the opposite experts
    of this sector don’t understand this. You must proceed your writing.
    I’m confident, you have a great readers’ base already!

  10. pieniadze [#]

    Thank you for the auspicious writeup. It in fact was a amusement account it.
    Look advanced to more added agreeable from you! By the way, how can we communicate?

  11. porn vedios [#]

    Muchos Gracias for your post. Really thank you! Really Cool.

  12. luxury replicas [#]

    Big Comparison Is Here: Fake Rolex VS Real

    The most popular watch models of luxury watch
    brands are sold at very high prices. As such, many
    people are turning to affordable watch alternatives of luxury watch brands.
    At this point, a confusion arises. Replica and fake
    watch confusion … In this article, we will touch on fake
    Rolex VS real and discuss the curious details. You can learn the difference between these
    two types of watches by reading our article. jf factory

  13. cialis buy [#]

    buy generic cialis online

  14. Seafood [#]

    Hello there, I found your site by way of Google even as searching for a related topic,
    your site got here up, it appears good. I have bookmarked it in my google bookmarks.

    Hi there, just become aware of your blog thru Google, and
    found that it is truly informative. I am going to watch
    out for brussels. I’ll appreciate for those who proceed this in future.
    Lots of people shall be benefited out of your
    writing. Cheers!

  15. Ojzgea [#]

    generic tadalafil at walmart – generic tadalafil canada canadian online pharmacy tadalafil

  16. ggifqdxkhx [#]

    Conoce cómo funciona el browser y optimiza tu código frontend | CSSLab | Laboratorio de ideas web
    aggifqdxkhx
    [url=http://www.g79142b2g6hu052n0z7x4tjourxh69e2s.org/]uggifqdxkhx[/url]
    ggifqdxkhx http://www.g79142b2g6hu052n0z7x4tjourxh69e2s.org/

  17. Ubukpq [#]

    tadalafil cheap tadalafil – tadalafil online pharmacy tadalafil citrate

  18. German Language [#]

    Excellent blog here! Additionally your web
    site a lot up fast! What web host are you the usage of?

    Can I am getting your associate link in your host? I wish my website loaded up as
    quickly as yours lol

  19. May tinh ban [#]

    It’s an amazing post in support of all the internet
    people; they will take advantage from it I am sure.

  20. nice airport taxi [#]

    Hello to all, how is everything, I think every one is getting more from this site, and your
    views are nice for new people.

    Have a look at my site; nice airport taxi

  21. https://www.thefalcoholic.com/users/kasyraseo [#]

    Hi, I think your website might be having browser compatibility issues.
    When I look at your website in Chrome, it looks fine
    but when opening in Internet Explorer, it has some overlapping.
    I just wanted to give you a quick heads up!

    Other then that, excellent blog!

  22. Keywords A [#]

    Keywords A

  23. Products [#]

    Products

  24. replica watches [#]

    Hi, I check your new stuff on a regular basis. Your story-telling style is awesome,
    keep up the good work!

  25. %url [#]

    It’s perfect time to make some plans for the long run and it is time to be happy.
    I’ve learn this submit and if I may just I want to suggest you some fascinating things or suggestions.
    Perhaps you can write subsequent articles relating to this article.

    I want to learn more things approximately it!

Deja tu Comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

CSSLab