La extracción e implementación del CSS crítico

Índice

El CSS es un lenguaje indispensable para que los navegadores puedan interpretar y expresar al usuario cómo son los elementos que componen una página web e incluso en algunos casos, cómo se comportan estos elementos.

Sin embargo, el CSS indebidamente gestionado puede plantear algunos inconvenientes que pueden manifestarse como pérdidas de rendimiento y que pueden ser causados por la declaración desmedida de reglas CSS innecesarias, el incorrecto modo de carga de los estilos, y algunos más.

En este artículo se abordará uno de los tantos métodos para extraer e implementar el CSS crítico, que es aquel necesario para renderizar los elementos que el usuario encontrará el contenido «above the fold», es decir aquel que puede verse tras la carga de la página sin necesidad de desplazarse en la navegación.

¿Con qué propósito se extrae el CSS crítico?

La extracción del CSS crítico tiene como objetivo extraer las reglas CSS que afectan con el contenido visible en la primera carga de la página, de modo que puedan ofrecerse al usuario de un modo anticipado (más rápido), a aquel CSS u otros recursos que el usuario no necesitará inicialmente.

Generalmente, la mayoría de sitios web utilizan múltiples hojas de estilo con diferentes propósitos y provenientes de diferentes orígenes. En el caso de aquellos sitios web basados en populares CMS como WordPress, Prestashop y algunos otros, se ha adoptado la costumbre poco eficiente de delegar las funcionalidades del sitio en plantillas, módulos o plugins que son soluciones prácticas y fáciles de implementar pero que al mismo tiempo son contrarias a los principios básicos del buen rendimiento, especialmente si su implementación se reduce a “instalar y activar”.

Un ejemplo puede ser el de la siguiente página de inicio de un comercio electrónico basado en Prestashop, donde se fuerza al usuario a descargar más de 70 hojas de estilo que no necesitará para ver correctamente el contenido que solicita, y que implica una descarga de 1.6mb de código CSS del cual únicamente son necesarios 127kb (8%).

CSS en desuso

¿Realmente es necesario cargar estilos de hojas de productos, o diferentes templates de páginas en la página de inicio? La respuesta es un rotundo no, y en los casos en que sea necesario se deberá a un desarrollo inapropiado.

Por tanto, el propósito de la extracción del CSS crítico y su posterior implementación es no obligar al navegador a descargar y procesar todos los archivos CSS para determinar qué estilos necesitará el usuario para ver el primer contenido visible, algo que se demorará una mayor cantidad de tiempo en función de la cantidad de código y recursos CSS que deban procesarse.

¿Cómo se extrae el CSS crítico?

Idealmente, la extracción e implementación del CSS crítico resuelve un problema que no debería existir de origen, y que debería contemplarse durante el desarrollo, sin embargo es algo poco frecuente ya que un elevado porcentaje de sitios web no contemplan las buenas prácticas del rendimiento, bien por desconocimiento u omisión por parte de equipos de desarrollo, o por presupuesto limitado del cliente.

La extracción puede realizarse de múltiples maneras y con diferentes herramientas, aunque en este caso utilizaremos la herramienta Critical desarrollada por Addy Osmany, Ingeniero de Google que a fecha de 2024 trabaja en el desarrollo de Chrome.

Critical es un módulo de npm, por lo que antes de continuar será necesario que cuentes con un entorno de Node.js listo para funcionar.

Critical permite la extracción del CSS crítico de manera personalizada, y aunque te invito a leer su documentación en Github, en este artículo abordaré las principales opciones de configuración.

Extracción sencilla con Critical

En primera línea siempre debe figurar la inclusión de Critical, y posteriormente deben declararse las opciones de configuración de Critical, en este ejemplo utilizaremos el método más sencillo:

// Importación 
import {generate} from 'critical';

// Configuración
generate({
  base: 'CSS/',
  src: 'https://www.guillermofr.com',
  target: 'critical.css',
  width: 1300,
  height: 900,
});

Resumidamente, estamos indicando a Critical que debe extraer el CSS crítico de la página de inicio de este propio sitio web, que debe crear una nueva carpeta llamada CSS en la misma carpeta donde se encuentra el archivo .mjs, y que dentro de ella debe insertar el CSS crítico para la resolución de 1300 píxeles de anchura y 900 píxeles de altura almacenándolo en el archivo critical.css.

Extracción para múltiples resoluciones

La mayoría de sitios web adaptan su diseño a las diferentes resoluciones de cada dispositivo, por lo que si únicamente servimos el CSS de resoluciones propias de ordenadores de escritorio, estaremos realizando una extracción incompleta, y cuya implementación supondría errores de diseño en las resoluciones no contempladas.

Mediante la configuración de dimensions, podemos declarar múltiples resoluciones de las que debe extraerse el CSS crítico.

Ejemplo:

generate({
  base: 'CSS/',
  src: 'https://www.guillermofr.com',
  target: {
    css: 'critical.css',
  },
  dimensions: [
    {
      height: 200,
      width: 500,
    },
    {
      height: 900,
      width: 1200,
    },
  ],
});

Otras opciones de configuración

Critical asume ciertos parámetros de configuración por defecto, como el caso de la anchura y la altura que, aunque no se declaren como en los ejemplos anteriores, siempre será de 1300 y 900 respectivamente.

En el caso del parámetro src:, hemos trabajado directamente con URLs públicas y accesibles para la herramienta, pero puede que te encuentres con que el destino no es accesible porque el servidor bloquee las conexiones que no provienen de usuarios reales. En casos como este, es importante saber que src: acepta también destinos locales como objetivo mediante la referencia al archivo local: src: ’index.html’ (que debería estar ubicado en la misma carpeta que el script desde el que ejecutamos Critical, excepto que se haga una declaración de directorio más concisa), por lo que podrían obtenerse los recursos de HTML y CSS objetivo, e instalarlos localmente para evitar el bloqueo.

De nuevo, te invito a recurrir a la documentación de Critical en Github donde podrás encontrar las diferentes formas en que la herramienta puede llevar a cabo la extracción.

¿Cómo se implementa el CSS crítico?

La implementación del CSS crítico consiste sencillamente en declarar el CSS extraído en etiquetas <style></style> antes de la descarga de cualquier otro recurso, pero esto puede ser algo más complejo de lo que parece, especialmente si se trabaja sobre un CMS.

Hay que tener en cuenta que el proceso de extracción de CSS crítico simplemente devuelve aquellos estilos que serán necesarios para la primera visualización de la carga y que posteriormente cargaremos en las etiquetas <style></style>, pero eso no significa que esas declaraciones CSS vayan a desaparecer en sus archivos de origen, por lo que al concluir la carga se habrán cargado dos veces las mismas declaraciones excepto que se depuren las hojas de estilo: algo inviable en algunas ocasiones. No se trata de algo óptimo, pero sí podría considerarse un perjuicio de menor tamaño con respecto al beneficio de esta práctica, aunque siempre que exista un control sobre las hojas de estilo será conveniente evitar las dobles declaraciones.

Existen múltiples soluciones para declarar el CSS crítico en diferentes CMS, pero una muy genérica y funcional que servirá en cualquier CMS o plataforma basada en PHP es la misma que se utiliza en este sitio web, y que consiste en declarar una función que servirá para extraer el contenido CSS de un archivo e imprimirlo prioritariamente entre etiquetas <style></style>, del siguiente modo:

// Se declara la función que recibirá como parámetro el tipo de página que hace la llamada
function generarCss($page) {
    // Si la llamada proviene de un artículo mediante el parámetro "single-post" ...
    if ($page === "single-post") {
        // Se extrae el contenido del archivo CSS y se incrusta entre etiquetas 
        echo "";
    }    
}

Y que posteriormente puede ser llamada desde el tipo de página en cuestión, en este caso desde single.php que es la nomenclatura de las plantillas para los artículos de WordPress:

<!-- Ejemplo simplificado de single.php en WordPress -->

<!DOCTYPE html>
<html lang="es">
<head>
    <!-- ... Etiquetas meta, title, etc... -->

    <!-- Solicitud del CSS crítico -->
    <?php generarCss("single-post"); ?>

    <!-- Carga del resto de recursos -->
</head>

<!-- Resto del código -->

De este modo, podemos mantener el CSS crítico localizado en un archivo y ofrecerlo con prioridad a los usuarios.

Esta sencilla función recibe un parámetro que debe asociarse al recurso CSS que debe declararse, por lo que puede -y debe- extenderse mediante la ampliación del condicional "if" (simplemente añadiendo nuevos elseif que contemplen otros parámetros) para trabajar con cualquier otro tipo de página: archivos de artículos o productos, productos sencillos o cualquier otro template que utilice el sitio web.

Casos en los que es más beneficiosa la extracción e incrustación del CSS crítico

Aquellos sitios web que sufren problemas de First Contentful Paint (FCP) son los que más pueden beneficiarse de esta práctica a nivel de SEO y experiencia de usuario, aunque siempre es recomendable seguir las buenas prácticas de desarrollo enfocadas al rendimiento, especialmente en la actualidad y en el futuro cercano, en previsión de que los motores de búsqueda -especialmente Google, quien lleva la delantera-, aprendan a evaluar el rendimiento de un sitio web de manera más exhaustiva y utilicen estas calificaciones como criterio de posicionamiento o indexación, algo que ya ocurre en la actualidad.

Mi recomendación personal es que utilices el método que te resulte más sencillo para extraer el CSS crítico, y que prestes especial atención en la implementación del mismo, ya que no en todas las ocasiones o entornos resultará viable implementarlo del mismo modo.