Evita los diseños grandes y complejos, y la paginación excesiva de diseños

El diseño es el aspecto a través del cual el navegador descifra la información geométrica de los elementos: su tamaño y ubicación en la página. Cada elemento posee información explícita o implícita sobre el tamaño, según la CSS empleada, el contenido del elemento o un elemento principal. El proceso se denomina "diseño" en Chrome.

El diseño es el aspecto a través del cual el navegador descifra la información geométrica de los elementos: su tamaño y ubicación en la página. Cada elemento posee información explícita o implícita sobre el tamaño, según la CSS empleada, el contenido del elemento o un elemento principal. El proceso se denomina Diseño en Chrome (y navegadores derivados, como Edge) y Safari. En Firefox, se denomina Reprocesamiento, pero el proceso es el mismo.

Al igual que en el caso de los cálculos de estilo, las inquietudes inmediatas relacionadas con los costos de diseño son las siguientes:

  1. La cantidad de elementos que requieren diseño, que es un subproducto del tamaño del DOM de la página.
  2. La complejidad de esos diseños.

Resumen

  • El diseño tiene un efecto directo en la latencia de interacción
  • El diseño generalmente se orienta a todo el documento.
  • La cantidad de elementos del DOM afectará el rendimiento; por ello, debes evitar la activación del diseño siempre que sea posible.
  • Evita los diseños sincrónicos forzados y la paginación excesiva de diseños; lee los valores de estilo y realiza cambios de estilo.

Efectos del diseño en la latencia de interacción

Cuando un usuario interactúa con la página, esas interacciones deben ser lo más rápidas posible. La cantidad de tiempo que tarda una interacción en completarse (que finaliza cuando el navegador presenta el siguiente fotograma para mostrar los resultados de la interacción) se conoce como latencia de interacción. Este es un aspecto del rendimiento de la página que mide la métrica Interaction to Next Paint.

La cantidad de tiempo que tarda el navegador en presentar el siguiente fotograma en respuesta a una interacción del usuario se conoce como retraso de presentación de la interacción. El objetivo de una interacción es proporcionar comentarios visuales para indicarle al usuario que ocurrió algo, y las actualizaciones visuales pueden implicar cierta cantidad de trabajo de diseño para lograr ese objetivo.

Para mantener el INP de tu sitio web lo más bajo posible, es importante evitar el diseño siempre que sea posible. Si no es posible evitar el diseño por completo, es importante limitar ese trabajo de diseño para que el navegador pueda presentar el siguiente fotograma rápidamente.

Evita el diseño siempre que sea posible

Cuando cambias los estilos, el navegador verifica si para alguno de los cambios es necesario calcular el diseño y si se debe actualizar el árbol de renderización. Para todos los cambios en las “propiedades geométricas”, como el ancho, la altura, la sección izquierda o la parte superior, se requiere diseño.

.box {
  width: 20px;
  height: 20px;
}

/**
  * Changing width and height
  * triggers layout.
  */

.box--expanded {
  width: 200px;
  height: 350px;
}

El diseño casi siempre se aplica a todo el documento. Si tienes muchos elementos, te tomará más tiempo descifrar las ubicaciones y las dimensiones de todos ellos.

Si no es posible evitar el diseño, la clave es, nuevamente, usar Chrome DevTools para ver cuánto tiempo tarda y determinar si el diseño es la causa del cuello de botella. Primero, abre DevTools, dirígete a la pestaña Timeline, presiona el botón Record e interactúa con tu sitio. Cuando dejes de grabar, verás un desglose del rendimiento de tu sitio:

DevTools muestra un tiempo prolongado en el diseño.

Si analizamos el seguimiento del ejemplo anterior, vemos que se dedican más de 28 milisegundos al diseño de cada fotograma, lo que es demasiado alto si tenemos 16 milisegundos para que en una animación aparezca un fotograma en la pantalla. También podrás ver que DevTools te indicará el tamaño del árbol (1,618 elementos en este caso) y la cantidad de nodos que necesitaban diseño (5 en este caso).

Ten en cuenta que el consejo general aquí es evitar el diseño siempre que sea posible, pero no siempre es posible evitarlo. En los casos en que no puedas evitar el diseño, ten en cuenta que el costo del diseño tiene una relación con el tamaño del DOM. Aunque la relación entre ambos no está estrechamente acoplada, los DOM más grandes suelen incurrir en costos de diseño más altos.

Evita los diseños síncronos forzados

El envío de un fotograma a la pantalla se realiza en este orden:

Usar Flexbox como diseño

Primero se ejecuta JavaScript, luego se realizan los cálculos de estilo y luego se aplica el diseño. Sin embargo, es posible forzar a un navegador a realizar el diseño de forma anticipada con JavaScript. Esto se denomina diseño sincrónico forzado.

Lo primero que se debe tener en cuenta es que, conforme JavaScript se ejecuta, puedes acceder a todos los valores de diseño del fotograma anterior para realizar consultas. Por lo tanto, si deseas definir la altura de un elemento (supongamos que es un “cuadro”) al inicio del fotograma, puedes escribir un código como el siguiente:

// Schedule our function to run at the start of the frame:
requestAnimationFrame(logBoxHeight);

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Se pueden generar problemas si cambiaste los estilos del cuadro antes de solicitar su altura:

function logBoxHeight () {
  box.classList.add('super-big');

  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Ahora bien, para poder responder la duda respecto de la altura, el navegador primero debe aplicar el cambio de estilo (debido a la adición de la clase super-big) y luego ejecutar el diseño. Solo entonces podrá devolver la altura correcta. Este es un trabajo innecesario y, potencialmente, costoso.

Por este motivo, siempre debes agrupar las lecturas de estilo y ejecutarlas primero (cuando el navegador puede usar los valores de diseño del fotograma anterior) y, luego, realizar las escrituras necesarias:

Si se hace correctamente, la función anterior debería verse de la siguiente manera:

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);

  box.classList.add('super-big');
}

En la mayoría de los casos, no debería ser necesario aplicar estilos y, luego, consultar valores; debería bastar con los valores del último fotograma. La ejecución de los cálculos de estilo y el diseño de forma sincrónica, y antes de lo que se esperaría para el navegador, supone posibles cuellos de botella y no es algo que normalmente te convendría hacer.

Evita la hiperpaginación del diseño

Existe una forma de complicar aún más la creación de diseños sincrónicos forzados: crear muchos diseños en una sucesión rápida. Observa este código:

function resizeAllParagraphsToMatchBlockWidth () {
  // Puts the browser into a read-write-read-write cycle.
  for (let i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = `${box.offsetWidth}px`;
  }
}

Este código se repite en un grupo de párrafos y establece el ancho del párrafo para que coincida con el ancho de un elemento llamado “box”. Si bien parece inofensivo, el problema es que en cada repetición del bucle se lee un valor de estilo (box.offsetWidth) y, luego, inmediatamente, se usa para actualizar el ancho de un párrafo (paragraphs[i].style.width). En la próxima repetición del bucle, el navegador debe tener en cuenta el hecho de que los estilos cambiaron desde que se solicitó offsetWidth por última vez (en la iteración anterior), y debe aplicar los cambios de estilo y ejecutar el diseño. Esto sucederá en cada una de las iteraciones.

La solución para este ejemplo consiste en, nuevamente, leer y, luego, escribir los valores:

// Read.
const width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth () {
  for (let i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = `${width}px`;
  }
}

Si quieres garantizar la seguridad, considera usar FastDOM, que agrupa automáticamente las lecturas y escrituras, y que te permite evitar la activación de diseños sincrónicos forzados o paginaciones excesivas de diseños de forma accidental.