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

Omite la renderización de 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 la 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. Como se omite la renderización, si una gran parte del contenido está fuera de la pantalla, puedes aprovechar la propiedad content-visibility para que el usuario inicial cargue mucho más rápido. También permite interacciones más rápidas con el contenido en pantalla. Estupendo.

demostración con figuras que representan los resultados de la red
En la demostración de nuestro artículo, aplicar content-visibility: auto a áreas de contenido fragmentado aumenta el rendimiento de la 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 dentro de la especificación de contención de CSS. Si bien por el momento content-visibility solo es compatible con Chromium 85 (y se considera que "vale la pena crear un prototipo" para Firefox), esta especificación es compatible con la mayoría de los navegadores modernos.

Contención de CSS

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

Básicamente, un desarrollador puede decirle 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é bits 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 con un valor potencial para la propiedad de CSS contain, que se puede combinar en una lista de valores separados por espacios:

  • size: La contención de tamaño en un elemento garantiza que el cuadro de este se pueda organizar 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 significa que los elementos subordinados no afectan el diseño externo de otros cuadros de la página. Esto nos permite omitir el diseño de los elementos subordinados si lo único que queremos hacer es diseñar otras cajas.
  • style: La contención del estilo garantiza que las propiedades que pueden tener efectos en más que solo sus elementos subordinados no escapen del elemento (p.ej., los contadores). Esto nos permite omitir potencialmente el procesamiento de estilo de los elementos subordinados si lo único que queremos es calcular estilos en otros elementos.
  • paint: La contención de la pintura garantiza que los descendientes del cuadro contenedor no se muestren fuera de sus límites. Nada puede desbordar visiblemente el elemento y, si un elemento está fuera de la pantalla o no es visible, sus elementos subordinados tampoco lo estarán. Esto nos permite omitir la pintura de los 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 adecuado. Puedes probar los valores para ver qué funciona mejor o puedes usar otra propiedad de CSS llamada content-visibility a fin de aplicar automáticamente la contención necesaria. content-visibility garantiza que obtengas las mayores ganancias de rendimiento que el navegador puede proporcionar con el mínimo esfuerzo de tu parte como desarrollador.

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

¿Qué significa? En resumen, si el elemento está fuera de la pantalla, sus elementos subordinados no se renderizan. El navegador determina el tamaño del elemento sin considerar ninguno de su contenido y se detiene ahí. Se omite la mayor parte de la renderización, como el estilo 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 a probar el contenido del elemento. Esto permite que el trabajo de renderización se realice justo a tiempo para que el usuario lo vea.

Nota sobre accesibilidad

Una de las funciones 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 al que se puede navegar sin esperar a que se cargue ni sacrifique el rendimiento de la renderización.

Sin embargo, la otra cara de esto 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 se encuentre fuera de la pantalla, ya que el navegador no renderizará estos estilos hasta que entren en el viewport. Para evitar que estos elementos se vean en el árbol de accesibilidad, lo que podría causar desorden, asegúrate de agregar también aria-hidden="true".

Ejemplo: un blog de viajes

En este ejemplo, mostramos nuestro blog de viajes a la derecha y aplicamos content-visibility: auto a áreas fragmentadas a la izquierda. Los resultados muestran que los tiempos de renderización 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 imágenes y texto descriptivo. Esto es lo que sucede en un navegador típico cuando navega a un blog de viajes:

  1. Se descarga una parte de la página de la red, junto con cualquier recurso necesario.
  2. El navegador diseña y presenta todos los contenidos 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 toda la página y los recursos.

En el paso 2, el navegador procesa todo el contenido en busca de aspectos que podrían haber cambiado. 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 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 procesa 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, diseñará y diseñará todos los contenidos que son visibles actualmente para el usuario (están en pantalla). Sin embargo, cuando se procese la 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.

La carga de esta página sería como si contuviera historias en pantalla completas y cuadros vacíos para cada una de las noticias fuera de pantalla. 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 de un tiempo de renderización de 232 ms a uno de 30 ms. El rendimiento aumenta 7 veces.

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

Captura de pantalla con anotaciones de la fragmentación del 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 Demostración en CodePen

Luego, aplicamos la siguiente regla de estilo a las secciones:

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

Especificación del tamaño natural de un elemento con contain-intrinsic-size

Para conocer los posibles beneficios de content-visibility, el navegador debe aplicar 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 diseñará 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 de tamaño. En nuestro ejemplo, se establece en 1000px como una estimación de la altura y el ancho de las secciones.

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

A partir de Chromium 98, 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, conservará el tamaño intrínseco renderizado. También se recordarán los cambios de tamaño de renderización posteriores. En la práctica, esto significa que, si te desplazas por un elemento con content-visibility: auto aplicado y, luego, lo vuelves a desplazar fuera de la pantalla, este conservará automáticamente su ancho y altura ideales, y no volverá al tamaño del marcador de posición. Esta función es particularmente útil para usuarios de desplazamiento infinito, que ahora pueden mejorar automáticamente la estimación de tamaño con el tiempo a medida que el usuario explora la página.

Ocultando contenido con content-visibility: hidden

¿Qué sucede si quieres que el contenido no se renderice, sin importar si está en pantalla o no, a la vez que aprovechas los beneficios del estado de renderización en caché? Ingresa content-visibility: hidden.

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

De esta manera, tendrás más control, ya que podrás 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 el elemento es tan costoso como renderizar un nuevo elemento con el mismo contenido.
  • visibility: hidden: Oculta el elemento y mantiene su estado de renderización. Esto no quita el elemento del documento, ya que este (y su subárbol) ocupa espacio geométrico en la página y se puede hacer clic en él de todos modos. También actualiza el estado de renderización cada vez que es necesario, incluso cuando está oculto.

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

Algunos casos de uso excelentes para 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 permite que la vista se renderice rápidamente cuando se vuelve a activar.

Efectos en la interacción con el siguiente procesamiento de imagen (INP)

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

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

Reducir el trabajo de renderización tiene un efecto directo en 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 la pantalla, le das al subproceso principal la oportunidad de responder a las tareas críticas visibles para el usuario. Esto puede mejorar el INP de tu página en algunas situaciones.

Conclusión

content-visibility y la Especificación de contención de CSS implican mejoras en el rendimiento interesantes para tu archivo CSS. Para obtener más información sobre estas propiedades, consulta: