Reduce el alcance y la complejidad de los cálculos de estilo

A menudo, JavaScript activa cambios visuales. En ocasiones, realiza esos cambios directamente mediante manipulaciones de diseño y, otras veces, mediante cálculos que generan cambios visuales, como la búsqueda o la ordenación de datos. El JavaScript sincronizado incorrectamente o de larga duración puede ser una causa común de los problemas de rendimiento, y debes intentar minimizar su impacto siempre que sea posible.

Cálculo de estilo

Si se modifica el DOM, se agregan y se quitan elementos, si se cambian los atributos o las clases, o se reproducen animaciones, el navegador vuelve a calcular los estilos de los elementos y, en muchos casos, el diseño de toda la página o parte de ella. Este proceso se denomina cálculo de estilo computado.

El navegador comienza a calcular estilos mediante la creación de un conjunto de selectores coincidentes para determinar qué clases, IDs y seudoselectores se aplican a un elemento determinado. Luego, procesa las reglas de estilo de los selectores coincidentes y determina los estilos finales que tiene el elemento.

Establece el estilo del tiempo de recálculo y la latencia de interacción

Interacción a la siguiente pintura (INP) es una métrica de rendimiento del entorno de ejecución centrada en el usuario que evalúa la capacidad de respuesta general de una página ante la entrada del usuario. Mide la latencia de interacción desde que el usuario interactúa con la página hasta que el navegador pinta el siguiente fotograma que muestra las actualizaciones visuales correspondientes de la interfaz de usuario.

Un componente significativo de una interacción es el tiempo que lleva pintar el siguiente fotograma. El trabajo de renderización que se realiza para presentar el siguiente fotograma se compone de muchas partes, incluido el cálculo de los diseños de página que ocurren justo antes del trabajo de diseño, pintura y composición. Esta página se enfoca en los costos de cálculo de diseño; sin embargo, si se reduce cualquier parte de la fase de renderización relacionada con la interacción, también se reduce su latencia total, incluidos los cálculos de diseño.

Reduce la complejidad de tus selectores

La simplificación de los nombres de los selectores puede ayudarte a acelerar los cálculos de estilo de tu página. Los selectores más simples hacen referencia a un elemento en CSS con solo un nombre de clase:

.title {
  /* styles */
}

Sin embargo, a medida que cualquier proyecto crece, es probable que necesite CSS más complejos, por lo que podrías tener selectores con el siguiente aspecto:

.box:nth-last-child(-n+1) .title {
  /* styles */
}

Para determinar cómo se aplican estos estilos a la página, el navegador debe preguntarse de manera efectiva: "¿Es un elemento con una clase de title cuyo elemento superior es el elemento secundario menos-nth-plus-1 con una clase de box?". Comprender esto puede llevar mucho tiempo, según el selector que se utilice y el navegador en cuestión. Para simplificar esto, puedes cambiar el selector para que sea solo un nombre de clase:

.final-box-title {
  /* styles */
}

Estos nombres de clases de reemplazo pueden parecer incómodos, pero simplifican mucho el trabajo del navegador. En la versión anterior, por ejemplo, para que el navegador sepa que un elemento es el último de su tipo, primero debe conocer todos los demás elementos a fin de determinar si algún elemento posterior podría ser nth-last-child. Esto puede ser mucho más costoso en términos de procesamiento que hacer coincidir un selector con un elemento solo porque su clase coincide.

Reduce la cantidad de elementos a los que se les aplica diseño

Otra consideración de rendimiento, y, a menudo, más importante que la complejidad del selector, es la cantidad de trabajo que debe realizarse cuando cambia un elemento.

En términos generales, el peor de los costos de calcular el estilo de los elementos calculados es la cantidad de elementos multiplicados por el recuento del selector, ya que el navegador debe verificar cada elemento al menos una vez con cada estilo para ver si coincide.

Los cálculos de diseño pueden orientarse directamente a algunos elementos en lugar de invalidar toda la página. En los navegadores modernos, esto suele ser un problema menor, ya que el navegador no siempre necesita verificar todos los elementos que un cambio podría afectar. Por otro lado, los navegadores más antiguos no siempre están optimizados para esas tareas. Siempre que puedas, debes reducir la cantidad de elementos invalidados.

Mide el costo de recalcular el estilo

Una forma de medir el costo de recalcular el estilo es usar el panel de rendimiento de las Herramientas para desarrolladores de Chrome. Para comenzar, haz lo siguiente:

  1. Abra Herramientas para desarrolladores.
  2. Ve a la pestaña Rendimiento.
  3. Haz clic en Grabar.
  4. Interactúa con la página.

Cuando detengas la grabación, verás una imagen similar a la siguiente:

Herramientas para desarrolladores que muestran los cálculos de estilo
Un informe de Herramientas para desarrolladores que muestra los cálculos de estilo.

La franja de la parte superior es un gráfico tipo llama en miniatura que también traza fotogramas por segundo. Cuanto más cercana esté la actividad a la parte inferior de la franja, más rápido el navegador pintará los marcos. Si ves que el gráfico tipo llama se nivela en la parte superior con barras rojas encima, significa que hay trabajo que causa fotogramas de larga duración.

Acercamiento de un área de problemas en las Herramientas para desarrolladores de Chrome en el resumen de actividad del panel de rendimiento propagado en las Herramientas para desarrolladores de Chrome.
Fotogramas de larga duración en el resumen de la actividad de Herramientas para desarrolladores.

Vale la pena analizar con más detalle los fotogramas de larga duración durante una interacción, como el desplazamiento. Si ves un bloque púrpura grande, acerca la actividad y selecciona cualquier trabajo con la etiqueta Recalculate Style para obtener más información sobre trabajos de recálculo de estilo potencialmente costosos.

Obtén los detalles de los cálculos de diseño de larga duración, incluida la información fundamental, como la cantidad de elementos afectados por el trabajo de nuevo cálculo de diseño.
Es un recálculo de estilo de larga duración que toma un poco más de 25 ms en el resumen de Herramientas para desarrolladores.

Cuando haces clic en el evento, se muestra su pila de llamadas. Si el trabajo de renderización se debió a una interacción del usuario, se llama al código JavaScript que activó el cambio de diseño. También muestra la cantidad de elementos a los que afecta el cambio (un poco más de 900 en este caso) y el tiempo que tardó el cálculo del diseño. Puedes usar esta información para empezar a tratar de encontrar una solución en tu código.

Usa Bloquear, Elemento y Modificador

Los enfoques de programación, como BEM (Bloque, elemento, modificador), se integran en los beneficios de rendimiento de coincidencia del selector. BEM recomienda que todo tenga una sola clase y, cuando necesitas jerarquía, esa jerarquía también se integra en el nombre de clase:

.list {
  /* Styles */
}

.list__list-item {
  /* Styles */
}

Si necesitas un modificador, como en el ejemplo del último elemento secundario, puedes agregarlo de la siguiente manera:

.list__list-item--last-child {
  /* Styles */
}

BEM es un buen punto de partida para organizar tu CSS, tanto desde la perspectiva de la estructura como debido a las simplificaciones de búsqueda de diseño que promueve.

Si no te gusta BEM, hay otras formas de abordar tu CSS, pero debes evaluar su rendimiento y ergonomía antes de comenzar.

Recursos

Hero image de Unsplash, de Markus Spiske.