content-visibility: la nueva propiedad de CSS que mejora el rendimiento de su renderización

Omite la renderización del contenido fuera de pantalla para mejorar el tiempo de carga inicial.

La propiedad content-visibility, que se lanzará en Chromium 85, podría ser una de las nuevas propiedades de CSS con mayor impacto para mejorar el rendimiento de carga de página. content-visibility permite que el usuario-agente omita el trabajo de renderización de un elemento, incluidos el diseño y la pintura, hasta que sea necesario. Debido a que se omite la renderización, si una gran parte del contenido está fuera de la pantalla, aprovechar la propiedad content-visibility hace que la carga inicial del usuario sea mucho más rápida. También permite interacciones más rápidas con el contenido en pantalla. Muy bien.

demostración con figuras que representan los resultados de la red
En nuestra demostración de artículo, aplicar content-visibility: auto a áreas de contenido fragmentado proporciona un aumento de rendimiento de renderización de 7 veces en la carga inicial. Continúa leyendo para obtener más información.

Navegadores compatibles

Navegadores compatibles

  • 85
  • 85
  • 124

Origen

content-visibility se basa en primitivas incluidas en las especificaciones de contención de CSS. Si bien, por el momento, content-visibility solo es compatible con Chromium 85 (y se considera "vale la pena" para Firefox), la especificación de contención es compatible con la mayoría de los navegadores.

Contención de CSS

El objetivo clave y general de la contención de CSS es habilitar las mejoras en el rendimiento de la renderización del contenido web mediante el aislamiento predecible de un subárbol del DOM del resto de la página.

Básicamente, un desarrollador puede indicarle a un navegador qué partes de la página están encapsuladas como un conjunto de contenido, lo que permite a los navegadores razonar sobre el contenido sin tener que considerar el estado fuera del subárbol. Saber qué fragmentos de contenido (subárboles) incluyen contenido aislado significa que el navegador puede tomar decisiones de optimización para la renderización de la página.

Existen cuatro tipos de contención de CSS, cada uno de los cuales es un valor potencial para la propiedad contain de CSS, que se puede combinar en una lista de valores separados por espacios:

  • size: La contención del tamaño en un elemento garantiza que el cuadro del elemento se pueda distribuir sin necesidad de examinar sus elementos subordinados. Eso significa que podemos omitir el diseño de los elementos subordinados si todo lo que necesitamos es el tamaño del elemento.
  • layout: La contención del diseño implica que los elementos subordinados no afectan el diseño externo de otros cuadros de la página. Esto nos permite omitir potencialmente el diseño de los elementos subordinados si lo único que queremos hacer es colocar otros cuadros.
  • style: La contención del diseño garantiza que las propiedades que pueden tener efectos en más que solo sus elementos subordinados no omitan el elemento (p.ej., contadores). Esto nos permite omitir el cálculo de estilo para los elementos subordinados si lo único que queremos es calcular estilos en otros elementos.
  • paint: La contención de la pintura garantiza que los elementos subordinados del cuadro contenedor no se muestren fuera de sus límites. Nada puede desbordar el elemento visiblemente y, si un elemento está fuera de la pantalla o no está visible, sus elementos subordinados tampoco serán visibles. Esto nos permite omitir potencialmente la pintura de los elementos subordinados si el elemento está fuera de la pantalla.

Cómo omitir el trabajo de renderización con content-visibility

Puede ser difícil determinar qué valores de contención usar, ya que las optimizaciones del navegador solo pueden iniciarse cuando se especifica un conjunto apropiado. Puedes experimentar con los valores para ver qué funciona mejor o puedes usar otra propiedad de CSS llamada content-visibility para aplicar automáticamente la contención necesaria. content-visibility garantiza que obtengas las mayores ganancias de rendimiento que el navegador puede proporcionar con un esfuerzo mínimo de tu parte como desarrollador.

La propiedad de visibilidad del contenido acepta varios valores, pero auto es la que proporciona mejoras inmediatas de rendimiento. Un elemento que tiene content-visibility: auto obtiene la contención de layout, style y paint. Si el elemento está fuera de la pantalla (y no es relevante para el usuario, los elementos relevantes serían los que tienen enfoque o selección en su subárbol), también obtiene la contención de size (y deja de pintar y realizar pruebas de posicionamiento de su contenido).

¿Qué significa? En resumen, si el elemento está fuera de la pantalla, no se renderizan sus elementos subordinados. El navegador determina el tamaño del elemento sin considerar ninguno de sus contenidos y se detiene ahí. Se omite la mayor parte de la renderización, como el diseño y el diseño del subárbol del elemento.

A medida que el elemento se acerca al viewport, el navegador ya no agrega la contención de size y comienza a pintar y realizar pruebas de posicionamiento del contenido del elemento. Esto permite que el trabajo de renderización se realice justo a tiempo para el usuario.

Nota sobre la accesibilidad

Una de las características de content-visibility: auto es que el contenido fuera de la pantalla permanece disponible en el modelo de objetos del documento y, por lo tanto, en el árbol de accesibilidad (a diferencia de visibility: hidden). Esto significa que se puede buscar contenido en la página y navegar a él sin esperar a que se cargue ni sacrificar el rendimiento de renderización.

La otra cara de esto, sin embargo, es que los elementos landmark con características de estilo como display: none o visibility: hidden también aparecerán en el árbol de accesibilidad cuando estén fuera de la pantalla, ya que el navegador no renderizará estos estilos hasta que ingresen al viewport. Para evitar que sean visibles en el árbol de accesibilidad y puedan causar desorden, asegúrate de agregar también aria-hidden="true".

Ejemplo: un blog de viajes

En este ejemplo, tomamos como referencia nuestro blog de viajes a la derecha y aplicamos content-visibility: auto a las áreas fragmentadas de la izquierda. Los resultados muestran tiempos de renderización que van de 232 ms a 30 ms en la carga inicial de la página.

Por lo general, un blog de viajes contiene un conjunto de historias con algunas fotos y un poco de texto descriptivo. A continuación, se muestra lo que sucede en un navegador típico cuando se navega a un blog de viajes:

  1. Una parte de la página se descarga de la red, junto con los recursos necesarios.
  2. El navegador diseña y presenta todo el contenido de la página, sin tener en cuenta si el contenido es visible para el usuario.
  3. El navegador regresa al paso 1 hasta que se descarguen la página y los recursos.

En el paso 2, el navegador procesa todo el contenido en busca de cambios. Actualiza el estilo y el diseño de cualquier elemento nuevo, junto con los elementos que pueden haber cambiado como resultado de nuevas actualizaciones. Este es un trabajo de renderización. Esto lleva tiempo.

Captura de pantalla de un blog de viajes.
Un ejemplo de un blog de viajes. Consulta la demostración en CodePen.

Ahora, considera lo que sucede si colocas content-visibility: auto en cada una de las historias individuales del blog. El bucle general es el mismo: el navegador descarga y renderiza fragmentos de la página. Sin embargo, la diferencia está en la cantidad de trabajo que realiza en el paso 2.

Con la visibilidad del contenido, se diseñarán y diseñarán todos los contenidos que son visibles actualmente para el usuario (en pantalla). Sin embargo, cuando se procesa una historia que está completamente fuera de la pantalla, el navegador omitirá el trabajo de renderización, y solo diseñará y diseñará el cuadro del elemento.

El rendimiento de cargar esta página sería como si contuviera historias en pantalla completas y cuadros vacíos para cada una de ellas. Esto funciona mucho mejor, con una reducción esperada del 50% o más del costo de renderización de la carga. En nuestro ejemplo, vemos un aumento que pasa de un tiempo de renderización de 232 ms a uno de 30 ms. lo que representa un aumento de 7 veces en el rendimiento.

¿Qué trabajo debes hacer para cosechar estos beneficios? Primero, fragmentamos el contenido en secciones:

Captura de pantalla con anotaciones que muestra cómo fragmentar contenido en secciones con una clase de CSS.
Ejemplo de fragmentación de contenido en secciones con la clase story aplicada para recibir content-visibility: auto. Consulta la demostración en CodePen.

A continuación, aplicamos la siguiente regla de estilo a las secciones:

.story {
  content-visibility: auto;
  contain-intrinsic-size: 1000px; /* Explained in the next section. */
}

Especifica el tamaño natural de un elemento con contain-intrinsic-size

Para aprovechar los beneficios potenciales de content-visibility, el navegador debe aplicar la contención de tamaño para garantizar que los resultados de renderización del contenido no afecten el tamaño del elemento de ninguna manera. Esto significa que el elemento se presentará como si estuviera vacío. Si el elemento no tiene una altura especificada en un diseño de bloque normal, será de 0.

Esto podría no ser ideal, ya que el tamaño de la barra de desplazamiento cambiará y dependerá de que cada historia tenga una altura distinta de cero.

Afortunadamente, CSS proporciona otra propiedad, contain-intrinsic-size, que especifica de manera efectiva el tamaño natural del elemento si este se ve afectado por la contención del tamaño. En nuestro ejemplo, lo configuramos en 1000px como estimación de la altura y el ancho de las secciones.

Esto significa que se presentará como si tuviera un solo elemento secundario de dimensiones de "tamaño intrínseco", lo que garantiza que los elementos div sin tamaño aún ocupen espacio. contain-intrinsic-size actúa como un tamaño de marcador de posición en lugar del contenido renderizado.

En Chromium 98 y versiones posteriores, hay una nueva palabra clave auto para contain-intrinsic-size. Cuando se especifique, el navegador recordará el último tamaño renderizado, si corresponde, y lo usará en lugar del tamaño del marcador de posición proporcionado por el desarrollador. Por ejemplo, si especificaste contain-intrinsic-size: auto 300px, el elemento comenzará con un tamaño intrínseco 300px en cada dimensión, pero, una vez que se renderice el contenido del elemento, este retendrá el tamaño intrínseco. También se recordarán todos los cambios posteriores en el tamaño de renderización. En la práctica, esto significa que, si te desplazas por un elemento con content-visibility: auto aplicado y, luego, lo desplazas fuera de la pantalla, retendrá automáticamente el ancho y la altura ideales, y no volverá al tamaño del marcador de posición. Esta función es especialmente útil para los desplazadores infinitos, que ahora pueden mejorar automáticamente la estimación del tamaño a lo largo del tiempo a medida que el usuario explora la página.

Ocultando contenido con content-visibility: hidden

¿Qué sucede si quieres mantener el contenido sin renderizar independientemente de si está o no en pantalla y, al mismo tiempo, aprovechar los beneficios del estado de renderización en caché? Ingresa: content-visibility: hidden.

La propiedad content-visibility: hidden ofrece los mismos beneficios del contenido no renderizado y el estado de renderización en caché que content-visibility: auto ofrece fuera de la pantalla. Sin embargo, a diferencia de auto, no comienza a renderizarse automáticamente en la pantalla.

Esto te otorga más control, ya que te permite ocultar el contenido de un elemento y, luego, mostrarlo con rapidez.

Compáralo con otras formas comunes de ocultar el contenido de los elementos:

  • display: none: Oculta el elemento y destruye su estado de renderización. Esto significa que mostrar un elemento es tan costoso como renderizar uno nuevo con el mismo contenido.
  • visibility: hidden: Oculta el elemento y mantiene su estado de renderización. Esto no quita realmente el elemento del documento, ya que (y su subárbol) aún ocupa espacio geométrico en la página y se puede hacer clic en él. También actualiza el estado de renderización cada vez que se necesita, incluso cuando está oculto.

content-visibility: hidden, por otro lado, oculta el elemento y conserva su estado de renderización, por lo que, si es necesario realizar algún cambio, solo se produce cuando se vuelve a mostrar el elemento (es decir, se quita la propiedad content-visibility: hidden).

Algunos de los mejores casos de uso de content-visibility: hidden son la implementación de desplazadores virtuales avanzados y la medición del diseño. También son ideales para aplicaciones de una sola página (SPA). Las vistas de apps inactivas se pueden dejar en el DOM con content-visibility: hidden aplicado para evitar que se muestren, pero mantener su estado almacenado en caché. Esto hace que la vista se renderice rápidamente cuando se vuelve a activar.

Efectos en la interacción con la siguiente pintura (INP)

INP es una métrica que evalúa la capacidad de una página para responder de manera confiable a las entradas del usuario. Cualquier cantidad excesiva de trabajo que ocurra en el subproceso principal, incluido el trabajo de renderización, puede afectar la capacidad de respuesta.

Siempre que puedas reducir el trabajo de renderización en una página determinada, le das al subproceso principal la oportunidad de responder con mayor rapidez a las entradas del usuario. Esto incluye el trabajo de renderización, y el uso de la propiedad content-visiblity de CSS cuando corresponda puede reducir el trabajo de renderización, especialmente durante el inicio, cuando se realiza la mayor parte del trabajo de renderización y diseño.

La reducción del trabajo de renderización tiene un efecto directo en el INP. Cuando los usuarios intentan interactuar con una página que usa la propiedad content-visibility de forma correcta para diferir el diseño y la renderización de los elementos fuera de pantalla, le das al subproceso principal la oportunidad de responder a trabajos críticos visibles para el usuario. Esto puede mejorar el INP de tu página en algunas situaciones.

Conclusión

content-visibility y las especificaciones de contención de CSS permiten que se implementen algunas mejoras de rendimiento interesantes para tu archivo CSS. Para obtener más información sobre estas propiedades, consulta lo siguiente: