Optimitzant el Critical Rendering Path
Una de les mètriques més utilitzades per mesurar i avaluar el rendiment, és el temps total de càrrega. És una mètrica realment important per valorar el rendiment, ja que estableix el temps total de càrrega de la nostra web.
Tot i ser un valor molt important, de cara a l’usuari no és l’únic que té en compte, ja que hi ha altres paràmetres que poden tenir una importància semblant, com per exemple, el temps que passa fins que es pot interactuar amb la web, o el temps que tarda a renderitzar el contingut principal.
Hi ha estudis d’usabilitat que indiquen que després d’un segon sense cap tipus de resposta, el nostre cervell perd l’atenció en el que fem i comença a prestar atenció a altres coses.
Prenent com a exemple la web de Mango (https://shop.mango.com) és impossible baixar el temps de càrrega a menys d’1 segon.
Però el que hem de tenir clar, és que no es tracta de carregar tota la web, només hem de carregar una part important o una part amb la que l’usuari pugui fer “alguna cosa”. D’aquesta manera mantenim el flux i la sensació de que la web està activa.
Per poder aconseguir aquest objectiu, hem d’entendre perfectament el que es necessita perquè un navegador renderitzi el contingut.
Com funciona el motor de renderitzat d’un navegador?
Els passos que segueix un navegador, són els següents:
- DOM (Document Object Model)
- CSS Object Model (CSSOM)
- Arbre del DOM
- Layout
- Renderitzat (pintat)
1. DOM (Document Object Model)
Per poder arribar al renderitzat final del DOM, el navegador ha de seguir 4 pasos:
- Convertir el bytes a caràcters
- Identificar tokens
- Convertir tokens a nodes
- Crear l’arbre de renderitzat

Aquests 4 pasos tenen un temps de processat, que pot ser més o menys gran en funció de la quantitat d’HTML que hagi de processar. Això vol dir que el processat del DOM té un cost sobre el rendiment.
Mentre el navegador està parsejant tot l’HTML per poder crear l’arbre del DOM, en el moment en el que troba un recurs CSS o Javascript, para l’execució i envia una petició i espera a rebre’ls. Quan ja el té segueix i repeteix el procés en cas de trobar més recursos.
Quan ha acabat de parsejar l’HTML i de fer les peticions per cadascun d’aquests recursos, el navegador té tot el contingut de la web, però per poder renderitzar la pàgina ha d’esperar al CSS Object Model (CSSOM), que li indica al navegador com ha de mostrar cadascun dels elements quan els renderitzi.
2. CSSOM (CSS Object Model)
Igual que amb l’HTML, el CSS s’ha de convertir a alguna cosa que el navegador pugui entendre, i per fer-ho es segueixen els següents pasos:
- Convertir bytes a caràctes
- Identificar tokens
- Convertir tokens a nodes
- Construir el CSSOM
En aquest pas l’intèrpret de CSS va llegint cadascun dels nodes i recull l’estil associat a cadascun d’ells.
El CSS és un dels elements més importants del CRP, ja que el navegador bloqueja l’execució fins que no ha recuperat i processat tots els CSS. Així que el CSS és un element de bloqueig de l’execució.
3. L’arbre de renderitzat
En aquest pas és on el navegador combina HTML i CSSOM, i el resultat és l’arbre de renderitzat, on hi ha tant el contingut com els estils de tot el contingut visible.
4. Layout
En aquest pas és on el navegador calcula el tamany i la posició de cadascun dels elements de la pàgina. Cada vegada que es canvia el tamany del viewport , el navegador ha de tornar a crear el layout de nou abans de tornar a ser pintat.
5. Renderitzat (Pintat)
Quan estem al pas de pintat, el navegador agafa el resultat del layout i el transforma en pixels a la pantalla. S’ha d’anar amb compte en aquesta etapa, ja que no tots els estils tenen el mateix temps de pintat. De la mateixa manera que les combinacions d’estils, tenen un temps de pintat més gran que per separat. Per exemple, barrejar border-radius
amb box-shadow
, pot trigar el triple que pintar-ne un de sol.
El torn del Javascript
El Javascript es tant potent, que ens permet fer modificacions tant al DOM com al CSSOM, així que per poder-lo executar, el navegador s’ha d’esperar al DOM, després esperar a descarregar els CSS, esperar a que acabi del CSSOM i només quan tot això ha acabat, executar el Javascript.
De la mateixa manera que amb el CSS, quan el parsejador del DOM troba un tag script bloqueja la construcció del DOM, espera a rebre el fitxer i que l’intèrpret de Javascript els parseji, així que el Javascript també és un bloquejador del rendertitzat.

En aquesta imatge podem veure la importància que té el CSSOM sobre el CRP, i com un sol event bloqueja tant el renderitzat com l’execució del javascript.
Només hi ha 2 casos on el Javascript no està bloquejat per el CSS:
- Quan els estils son
in-line
i estan per sobre dels tags<link>
i dins del<head>
- Els
scripts
carregats de manera asíncrona
Carregar el javascript de manera asíncrona
Els scripts asíncrons no bloquejen la construcció del DOM i no hem d’esperar a l’event CSSOM. D’aquesta manera tindrem el CRP lliure de bloquejos de Javascript. Aques punt és una part essencial de la optimització del CRP.
Com optimitzar el CRP
Pel que sabem de moment, podríem dir que per millor el CRP hem d’estar pendents de 3 coses: tamany de l’HTML, entrega del CSS i carregar asíncronament els fitxers Javascript.
Entenent el CRP
Anem a suposar que a la nostra web carregarem 1 fitxer CSS i 1 fitxer Javascript.

En aquest exemple tenim 2 recursos crítics, l’HTML i el CSS (el Javascript és asíncron, així que no interfereix), que sumen un total de 46kb al nostre CRP, que equivalen a les 2 peticions.
Com podem optimitzar-ho?
Primer de tot, hem de fer els fitxers el més petits possible, minificant i comprimint tant HTML com CSS. Ofuscant-los encara podem portar més enllà aquest pas. La ofuscació és el procés de convertir, tant a l’HTML com al CSS, les classes de “.nav-main-button” a “.a_123”. Fent que estalvien encara uns bytes extres.
Proper pas: optimitzar l’entrega
Un cop tenim els recursos optimitzats al màxim possible, el que hem de fer és servir-los al client el més ràpid possible. Incloure els CSS en línia dins de l’HTML, és una bona opció, ja que amb una sola petició (HTML) recuperem el DOM i el CSSOM.
Però, el que no podem fer, és incloure un fitxer de 46kb dins de l’HTML, tot i que podria ser que carregués més ràpid que amb un fitxer extern, afegir un petició tant gran de manera inicial, pot fer que les coses no acabin de funcionar del tot bé.
Una bona estratègia però, seria incloure només els CSS del header i del contingut pricipal, i asíncronament la resta del CSS. D’aquesta manera fem una petita càrrega d’estils, evitant un “flash” d’informació sense estils, i no bloquegem l’execució de la resta del DOM.
Eines disponibles:
https://github.com/filamentgroup/loadCSS
En el cas que la nostra web utilitzi web fonts, és indispensable carregar-les de manera asíncrona. Si no ho fem així, ho tindríem tot carregat, però l’usuari podria no veure el text perquè encara no hi hauria la font carregada.
Més informació sobre com carregar fonts de manera asíncrona:
http://www.sitepoint.com/improving-font-performance-subsetting-local-storage/
Obtenció del primer render
Donant per fet que hem fet tots els pasos anteriors, ara tocar veure si la nostra web carrega amb menys d’1 segon.
…the server can send up to 10 TCP packets on a new connection (~14KB) in first roundtrip, and then it must wait for the client to acknowledge this data before it can grow its congestion window and proceed to deliver more data.
Due to this TCP behavior, it is important to optimize your content to minimize the number of roundtrips required to deliver the necessary data to perform the first render of the page. Ideally, the ATF (above the fold) content should fit under 14KB — this allows the browser to paint the page after just one roundtrip…
Fent cas de la informació anterior i tenint com a objectiu carregar la web amb menys d’1 segon, hem de fer que tant l’HTML com el CSS crític pesin, més o menys, 14kb. Hauríem de carregar el header i el contingut principal, com a mínim, dins d’aquesta càrrega inicial.

Després de carregar els 14kb inicials, hem de renderitzar el contingut, però el procés de parsejar l’HTML, el CSS, i executar el Javascript requereix temps i recursos, i amb una connexió 3G tenim una sobrecàrrega de ~600ms (una conncexió 4G redueix una mica aquest temps), després hem d’esperar uns 200ms de resposta del servidor, i ens queden 200ms per parsejar l’HTML i el CSS, de tal manera que mantenir les coses el més simples possible hi ajuda (aquest és un dels principis bàsics del disseny mobile first).
Si s’han aplicats tots els pasos i s’han fet totes les optimitzacions recomenades anteriorment, enhorabona, hauriem de ser capaços de generar una experiència quasi instantànea.
Conclusions
Entendre com un navegador treballa i com gestiona el contingut necessari per renderitzar una pàgina, és una part essencial per poder optimitzar el Critical Rendering Path.
També la simplicitat del disseny i tenir present el rendiment des del primer dia, són elements essencials per aconseguir el sant grial de la experipència instantània. No podrem entregar el contingut principal amb menys d’un segon si només prioritzem un disseny extremadament complex.
I sempre és millor, carregar alguna part el més ràpid possible, que no fer esperar l’usuari amb una pantalla en blanc, fins tenir tot el contingut.