Rendimiento front-end 2021: Optimizaciones de activos
Publicado: 2022-03-10Esta guía ha sido amablemente respaldada por nuestros amigos de LogRocket, un servicio que combina la supervisión del rendimiento de frontend , la reproducción de sesiones y el análisis de productos para ayudarlo a crear mejores experiencias para los clientes. LogRocket rastrea métricas clave, incl. DOM completo, tiempo hasta el primer byte, primer retardo de entrada, CPU del cliente y uso de memoria. Obtenga una prueba gratuita de LogRocket hoy.
Tabla de contenido
- Preparándose: planificación y métricas
- Establecer metas realistas
- Definición del entorno
- Optimizaciones de activos
- Optimizaciones de compilación
- Optimizaciones de entrega
- Redes, HTTP/2, HTTP/3
- Pruebas y monitoreo
- Triunfos rápidos
- Todo en una página
- Descargar la lista de verificación (PDF, Apple Pages, MS Word)
- Suscríbase a nuestro boletín de correo electrónico para no perderse las próximas guías.
Optimizaciones de activos
- Utilice Brotli para la compresión de texto sin formato.
En 2015, Google presentó Brotli, un nuevo formato de datos sin pérdidas de código abierto, que ahora es compatible con todos los navegadores modernos. La biblioteca Brotli de código abierto, que implementa un codificador y decodificador para Brotli, tiene 11 niveles de calidad predefinidos para el codificador, con un nivel de calidad más alto que exige más CPU a cambio de una mejor relación de compresión. Una compresión más lenta conducirá en última instancia a tasas de compresión más altas, pero aún así, Brotli se descomprime rápidamente. Sin embargo, vale la pena señalar que Brotli con el nivel de compresión 4 es más pequeño y se comprime más rápido que Gzip.En la práctica, Brotli parece ser mucho más efectivo que Gzip. Las opiniones y las experiencias difieren, pero si su sitio ya está optimizado con Gzip, es posible que espere mejoras de al menos un dígito y, en el mejor de los casos, mejoras de dos dígitos en la reducción de tamaño y los tiempos de FCP. También puede estimar los ahorros de compresión de Brotli para su sitio.
Los navegadores aceptarán Brotli solo si el usuario visita un sitio web a través de HTTPS. Brotli es ampliamente compatible y muchas CDN lo admiten (Akamai, Netlify Edge, AWS, KeyCDN, Fastly (actualmente solo como transferencia), Cloudflare, CDN77) y puede habilitar Brotli incluso en CDN que aún no lo admiten. (con un trabajador de servicio).
El problema es que debido a que comprimir todos los activos con Brotli a un alto nivel de compresión es costoso, muchos proveedores de alojamiento no pueden usarlo a toda escala solo por el enorme costo general que produce. De hecho, en el nivel más alto de compresión, Brotli es tan lento que cualquier ganancia potencial en el tamaño del archivo podría verse anulada por la cantidad de tiempo que le toma al servidor comenzar a enviar la respuesta mientras espera para comprimir dinámicamente el activo. (Pero si tiene tiempo durante el tiempo de compilación con compresión estática, por supuesto, se prefieren configuraciones de compresión más altas).
Aunque esto podría estar cambiando. El formato de archivo Brotli incluye un diccionario estático incorporado y, además de contener varias cadenas en varios idiomas, también admite la opción de aplicar múltiples transformaciones a esas palabras, lo que aumenta su versatilidad. En su investigación, Felix Hanau ha descubierto una manera de mejorar la compresión en los niveles 5 a 9 usando "un subconjunto más especializado del diccionario que el predeterminado" y confiando en el encabezado
Content-Type
para decirle al compresor si debe usar un diccionario para HTML, JavaScript o CSS. El resultado fue un "impacto insignificante en el rendimiento (1 % a 3 % más de CPU en comparación con el 12 % normal) al comprimir contenido web a altos niveles de compresión, utilizando un enfoque de uso de diccionario limitado".Además de eso, con la investigación de Elena Kirilenko, podemos lograr una recompresión de Brotli rápida y eficiente utilizando artefactos de compresión anteriores. Según Elena, "una vez que tenemos un activo comprimido a través de Brotli, y tratamos de comprimir contenido dinámico sobre la marcha, donde el contenido se parece al contenido disponible para nosotros con anticipación, podemos lograr mejoras significativas en los tiempos de compresión. "
¿Con qué frecuencia es el caso? Por ejemplo, con la entrega de subconjuntos de paquetes de JavaScript (por ejemplo, cuando partes del código ya están almacenadas en caché en el cliente o con paquetes dinámicos sirviendo con WebBundles). O con HTML dinámico basado en plantillas conocidas de antemano, o fuentes WOFF2 subdivididas dinámicamente . Según Elena, podemos obtener una mejora del 5,3 % en la compresión y una mejora del 39 % en la velocidad de compresión al eliminar el 10 % del contenido, y un 3,2 % de mejores tasas de compresión y una compresión un 26 % más rápida, al eliminar el 50 % del contenido.
La compresión de Brotli está mejorando, por lo que si puede evitar el costo de comprimir dinámicamente los activos estáticos, definitivamente vale la pena el esfuerzo. No hace falta decir que Brotli se puede usar para cualquier carga útil de texto sin formato: HTML, CSS, SVG, JavaScript, JSON, etc.
Nota : a principios de 2021, aproximadamente el 60 % de las respuestas HTTP se envían sin compresión basada en texto, con un 30,82 % comprimiendo con Gzip y un 9,1 % comprimiendo con Brotli (tanto en dispositivos móviles como en computadoras de escritorio). Por ejemplo, el 23,4 % de las páginas de Angular no están comprimidas (a través de gzip o Brotli). Sin embargo, a menudo activar la compresión es una de las victorias más fáciles para mejorar el rendimiento con solo presionar un interruptor.
¿La estrategia? Comprima previamente los activos estáticos con Brotli+Gzip en el nivel más alto y comprima HTML (dinámico) sobre la marcha con Brotli en el nivel 4–6. Asegúrese de que el servidor maneje la negociación de contenido para Brotli o Gzip correctamente.
- ¿Utilizamos la carga de medios adaptativos y sugerencias de clientes?
Viene de la tierra de las noticias antiguas, pero siempre es un buen recordatorio para usar imágenes receptivas consrcset
,sizes
y el elemento<picture>
. Especialmente para los sitios con una gran huella de medios, podemos ir un paso más allá con la carga de medios adaptativa (en este ejemplo, React + Next.js), brindando una experiencia liviana para redes lentas y dispositivos con poca memoria y una experiencia completa para redes rápidas y alta. -dispositivos de memoria. En el contexto de React, podemos lograrlo con sugerencias de clientes en el servidor y ganchos adaptativos de reacción en el cliente.El futuro de las imágenes receptivas podría cambiar drásticamente con la adopción más amplia de las sugerencias de los clientes. Las sugerencias del cliente son campos de encabezado de solicitud HTTP, por ejemplo,
DPR
,Viewport-Width
,Width
,Save-Data
,Accept
(para especificar preferencias de formato de imagen) y otros. Se supone que deben informar al servidor sobre los detalles del navegador, la pantalla, la conexión, etc. del usuario.Como resultado, el servidor puede decidir cómo completar el diseño con imágenes del tamaño adecuado y servir solo estas imágenes en los formatos deseados. Con las sugerencias del cliente, movemos la selección de recursos del marcado HTML a la negociación de solicitud-respuesta entre el cliente y el servidor.
Como señaló Ilya Grigorik hace un tiempo, las sugerencias de los clientes completan la imagen: no son una alternativa a las imágenes receptivas. "El elemento
<picture>
proporciona el control de dirección de arte necesario en el marcado HTML. Las sugerencias del cliente proporcionan anotaciones en las solicitudes de imágenes resultantes que permiten la automatización de la selección de recursos. Service Worker proporciona capacidades completas de gestión de solicitudes y respuestas en el cliente".Un trabajador de servicio podría, por ejemplo, agregar nuevos valores de encabezados de sugerencias de clientes a la solicitud, reescribir la URL y apuntar la solicitud de imagen a un CDN, adaptar la respuesta en función de la conectividad y las preferencias del usuario, etc. para casi todas las demás solicitudes también.
Para los clientes que admiten sugerencias de clientes, se podría medir un 42 % de ahorro de bytes en imágenes y 1 MB+ menos de bytes para el percentil 70+. En Smashing Magazine, también pudimos medir una mejora del 19 al 32 %. Las sugerencias de clientes son compatibles con los navegadores basados en Chromium, pero aún se están considerando en Firefox.
Sin embargo, si proporciona tanto el marcado de imágenes receptivas normales como la etiqueta
<meta>
para Client Hints, entonces un navegador compatible evaluará el marcado de imágenes receptivas y solicitará la fuente de imagen adecuada utilizando los encabezados HTTP de Client Hints. - ¿Usamos imágenes receptivas para las imágenes de fondo?
¡Seguramente deberíamos! Conimage-set
, ahora compatible con Safari 14 y con la mayoría de los navegadores modernos excepto Firefox, también podemos ofrecer imágenes de fondo receptivas:background-image: url("fallback.jpg"); background-image: image-set( "photo-small.jpg" 1x, "photo-large.jpg" 2x, "photo-print.jpg" 600dpi);
Básicamente, podemos servir de forma condicional imágenes de fondo de baja resolución con un descriptor de
1x
e imágenes de mayor resolución con un descriptor de2x
, e incluso una imagen de calidad de impresión con un descriptor de600dpi
. Sin embargo, tenga cuidado: los navegadores no brindan ninguna información especial sobre las imágenes de fondo para la tecnología de asistencia, por lo que, idealmente, estas fotos serían meramente decorativas. - ¿Usamos WebP?
La compresión de imágenes a menudo se considera una ganancia rápida, sin embargo, todavía está muy infrautilizada en la práctica. Por supuesto, las imágenes no bloquean el renderizado, pero contribuyen en gran medida a las bajas puntuaciones de LCP y, muy a menudo, son demasiado pesadas y demasiado grandes para el dispositivo en el que se consumen.Entonces, como mínimo, podríamos explorar el uso del formato WebP para nuestras imágenes. De hecho, la saga WebP estuvo llegando a su fin el año pasado cuando Apple agregó soporte para WebP en Safari 14. Entonces, después de muchos años de discusiones y debates, a partir de hoy, WebP es compatible con todos los navegadores modernos. Por lo tanto, podemos servir imágenes WebP con el elemento
<picture>
y un respaldo JPEG si es necesario (consulte el fragmento de código de Andreas Bovens) o mediante la negociación de contenido (usando encabezados deAccept
).Sin embargo, WebP no está exento de inconvenientes . Si bien los tamaños de archivo de imagen de WebP se comparan con Guetzli y Zopfli equivalentes, el formato no es compatible con la representación progresiva como JPEG, por lo que los usuarios pueden ver la imagen terminada más rápido con un buen JPEG, aunque las imágenes de WebP pueden ser más rápidas a través de la red. Con JPEG, podemos ofrecer una experiencia de usuario "decente" con la mitad o incluso la cuarta parte de los datos y cargar el resto más tarde, en lugar de tener una imagen medio vacía como en el caso de WebP.
Su decisión dependerá de lo que esté buscando: con WebP, reducirá la carga útil y con JPEG mejorará el rendimiento percibido. Puede obtener más información sobre WebP en WebP Rewind talk de Pascal Massimino de Google.
Para la conversión a WebP, puede usar WebP Converter, cwebp o libwebp. Ire Aderinokun también tiene un tutorial muy detallado sobre cómo convertir imágenes a WebP, al igual que Josh Comeau en su artículo sobre la adopción de formatos de imagen modernos.
Sketch es compatible de forma nativa con WebP, y las imágenes de WebP se pueden exportar desde Photoshop utilizando un complemento de WebP para Photoshop. Pero también hay otras opciones disponibles.
Si está utilizando WordPress o Joomla, existen extensiones para ayudarlo a implementar fácilmente la compatibilidad con WebP, como Optimus y Cache Enabler para WordPress y la propia extensión compatible de Joomla (a través de Cody Arsenault). También puede abstraer el elemento
<picture>
con React, componentes con estilo o gatsby-image.¡Ah, enchufe desvergonzado! — Jeremy Wagner incluso publicó un libro Smashing sobre WebP que tal vez desee consultar si está interesado en todo lo relacionado con WebP.
- ¿Utilizamos AVIF?
Es posible que haya escuchado la gran noticia: AVIF ha aterrizado. Es un nuevo formato de imagen derivado de los fotogramas clave del video AV1. Es un formato abierto y libre de regalías que admite compresión con pérdida y sin pérdida, animación, canal alfa con pérdida y puede manejar líneas nítidas y colores sólidos (que era un problema con JPEG), al tiempo que proporciona mejores resultados en ambos.De hecho, en comparación con WebP y JPEG, AVIF funciona significativamente mejor , lo que genera un ahorro de tamaño de archivo promedio de hasta un 50 % con el mismo DSSIM ((des)similitud entre dos o más imágenes usando un algoritmo que se aproxima a la visión humana). De hecho, en su publicación completa sobre la optimización de la carga de imágenes, Malte Ubl señala que AVIF "supera consistentemente a JPEG de una manera muy significativa. Esto es diferente de WebP, que no siempre produce imágenes más pequeñas que JPEG y en realidad puede ser una red. pérdida por falta de apoyo para la carga progresiva".
Irónicamente, AVIF puede funcionar incluso mejor que los SVG grandes, aunque, por supuesto, no debe verse como un reemplazo de los SVG. También es uno de los primeros formatos de imagen que admite soporte de color HDR; ofreciendo mayor brillo, profundidad de bits de color y gamas de colores. El único inconveniente es que actualmente AVIF no admite la decodificación progresiva de imágenes (¿todavía?) y, de manera similar a Brotli, una codificación de alta tasa de compresión actualmente es bastante lenta, aunque la decodificación es rápida.
Actualmente, AVIF es compatible con Chrome, Firefox y Opera, y se espera que pronto sea compatible con Safari (ya que Apple es miembro del grupo que creó AV1).
Entonces, ¿cuál es la mejor manera de publicar imágenes en estos días ? Para ilustraciones e imágenes vectoriales, SVG (comprimido) es sin duda la mejor opción. Para las fotos, usamos métodos de negociación de contenido con el elemento de
picture
. Si se admite AVIF, enviamos una imagen AVIF; si no es el caso, primero recurrimos a WebP, y si WebP tampoco es compatible, cambiamos a JPEG o PNG como respaldo (aplicando las condiciones de@media
si es necesario):<picture> <source type="image/avif"> <source type="image/webp"> <img src="image.jpg" alt="Photo" width="450" height="350"> </picture>
Francamente, es más probable que usemos algunas condiciones dentro del elemento de
picture
:<picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>
<picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>
Puede ir aún más lejos intercambiando imágenes animadas con imágenes estáticas para los clientes que optan por menos movimiento con movimiento
prefers-reduced-motion
:<picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>
<picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>
Durante el par de meses, AVIF ha ganado bastante tracción:
- Podemos probar los respaldos de WebP/AVIF en el panel Rendering en DevTools.
- Podemos usar Squoosh, AVIF.io y libavif para codificar, decodificar, comprimir y convertir archivos AVIF.
- Podemos usar el componente AVIF Preact de Jake Archibald que decodifica un archivo AVIF en un trabajador y muestra el resultado en un lienzo,
- Para entregar AVIF solo a navegadores compatibles, podemos usar un complemento PostCSS junto con un script 315B para usar AVIF en sus declaraciones CSS.
- Podemos entregar progresivamente nuevos formatos de imagen con CSS y Cloudlare Workers para modificar dinámicamente el documento HTML devuelto, deducir información del encabezado de
accept
y luego agregar laswebp/avif
, etc., según corresponda. - AVIF ya está disponible en Cloudinary (con límites de uso), Cloudflare admite AVIF en el cambio de tamaño de imagen y puede habilitar AVIF con encabezados AVIF personalizados en Netlify.
- Cuando se trata de animación, AVIF funciona tan bien como
<img src=mp4>
de Safari, superando a GIF y WebP en general, pero MP4 aún funciona mejor. - En general, para animaciones, AVC1 (h264) > HVC1 > WebP > AVIF > GIF, suponiendo que los navegadores basados en Chromium alguna vez admitirán
<img src=mp4>
. - Puede encontrar más detalles sobre AVIF en AVIF para la charla de codificación de imágenes de próxima generación de Aditya Mavlankar de Netflix, y la charla de The AVIF Image Format de Kornel Lesinski de Cloudflare.
- Una gran referencia para todo lo relacionado con AVIF: ha llegado la publicación completa de Jake Archibald sobre AVIF.
¿Entonces es el futuro AVIF ? Jon Sneyers no está de acuerdo: AVIF funciona un 60 % peor que JPEG XL, otro formato gratuito y abierto desarrollado por Google y Cloudinary. De hecho, JPEG XL parece estar funcionando mucho mejor en todos los ámbitos. Sin embargo, JPEG XL aún se encuentra en las etapas finales de estandarización y aún no funciona en ningún navegador. (No se mezcle con el JPEG-XR de Microsoft que viene del buen Internet Explorer 9 veces).
- ¿Están JPEG/PNG/SVG correctamente optimizados?
Cuando esté trabajando en una página de destino en la que es fundamental que una imagen destacada se cargue ultrarrápidamente, asegúrese de que los archivos JPEG sean progresivos y estén comprimidos con mozJPEG (que mejora el tiempo de inicio de procesamiento al manipular los niveles de escaneo) o Guetzli, el código abierto de Google. codificador centrado en el rendimiento perceptivo y utilizando aprendizajes de Zopfli y WebP. El único inconveniente: tiempos de procesamiento lentos (un minuto de CPU por megapíxel).Para PNG, podemos usar Pingo y para SVG, podemos usar SVGO o SVGOMG. Y si necesita obtener una vista previa y copiar o descargar rápidamente todos los activos SVG de un sitio web, svg-grabber también puede hacerlo por usted.
Cada artículo de optimización de imágenes lo indicaría, pero siempre vale la pena mencionar mantener los activos vectoriales limpios y ajustados. Asegúrese de limpiar los activos no utilizados, elimine los metadatos innecesarios y reduzca la cantidad de puntos de ruta en las ilustraciones (y, por lo tanto, en el código SVG). ( ¡Gracias, Jeremy! )
Sin embargo, también hay herramientas útiles en línea disponibles:
- Use Squoosh para comprimir, cambiar el tamaño y manipular imágenes en los niveles de compresión óptimos (con pérdida o sin pérdida),
- Use Guetzli.it para comprimir y optimizar imágenes JPEG con Guetzli, que funciona bien para imágenes con bordes nítidos y colores sólidos (pero puede ser un poco más lento).
- Utilice el Generador de puntos de interrupción de imágenes sensibles o un servicio como Cloudinary o Imgix para automatizar la optimización de imágenes. Además, en muchos casos, el uso exclusivo de
srcset
ysizes
generará beneficios significativos. - Para verificar la eficiencia de su marcado receptivo, puede usar el montón de imágenes, una herramienta de línea de comandos que mide la eficiencia en los tamaños de ventana gráfica y las proporciones de píxeles del dispositivo.
- Puede agregar compresión automática de imágenes a sus flujos de trabajo de GitHub, de modo que ninguna imagen llegue a la producción sin comprimir. La acción usa mozjpeg y libvips que funcionan con PNG y JPG.
- Para optimizar el almacenamiento de forma interna, puede usar el nuevo formato Lepton de Dropbox para comprimir archivos JPEG sin pérdidas en un promedio del 22 %.
- Use BlurHash si desea mostrar una imagen de marcador de posición antes. BlurHash toma una imagen y le da una cadena corta (¡solo 20-30 caracteres!) que representa el marcador de posición para esta imagen. La cadena es lo suficientemente corta como para que se pueda agregar fácilmente como un campo en un objeto JSON.
A veces, la optimización de imágenes por sí sola no es suficiente. Para mejorar el tiempo necesario para iniciar la renderización de una imagen crítica, cargue de forma diferida las imágenes menos importantes y posponga la carga de cualquier script después de que las imágenes críticas ya se hayan renderizado. La forma más segura es la carga diferida híbrida, cuando utilizamos carga diferida nativa y carga diferida, una biblioteca que detecta cualquier cambio de visibilidad desencadenado a través de la interacción del usuario (con IntersectionObserver, que exploraremos más adelante). Adicionalmente:
- Considere precargar imágenes críticas, para que un navegador no las descubra demasiado tarde. Para las imágenes de fondo, si desea ser aún más agresivo que eso, puede agregar la imagen como una imagen normal con
<img src>
y luego ocultarla de la pantalla. - Considere intercambiar imágenes con el atributo de tamaños especificando diferentes dimensiones de visualización de imágenes según las consultas de medios, por ejemplo, para manipular
sizes
para intercambiar fuentes en un componente de lupa. - Revise las inconsistencias en la descarga de imágenes para evitar descargas inesperadas de imágenes de primer plano y de fondo. Tenga cuidado con las imágenes que se cargan de forma predeterminada, pero es posible que nunca se muestren, por ejemplo, en carruseles, acordeones y galerías de imágenes.
- Asegúrese de establecer siempre el
width
y elheight
en las imágenes. Tenga cuidado con la propiedadaspect-ratio
en CSS y el atributo de tamañointrinsicsize
que nos permitirá establecer relaciones de aspecto y dimensiones para las imágenes, de modo que el navegador pueda reservar un espacio de diseño predefinido con anticipación para evitar saltos de diseño durante la carga de la página.
Si se siente aventurero, puede cortar y reorganizar las transmisiones HTTP/2 utilizando trabajadores de Edge, básicamente un filtro en tiempo real que vive en la CDN, para enviar imágenes más rápido a través de la red. Los trabajadores de borde usan flujos de JavaScript que usan fragmentos que puede controlar (básicamente, son JavaScript que se ejecuta en el borde de CDN que puede modificar las respuestas de transmisión), por lo que puede controlar la entrega de imágenes.
Con un trabajador de servicio, es demasiado tarde ya que no puede controlar lo que está en el cable, pero funciona con los trabajadores de Edge. Por lo tanto, puede usarlos sobre archivos JPEG estáticos guardados progresivamente para una página de destino en particular.
¿No es suficiente? Bueno, también puede mejorar el rendimiento percibido de las imágenes con la técnica de múltiples imágenes de fondo. Tenga en cuenta que jugar con el contraste y difuminar detalles innecesarios (o eliminar colores) también puede reducir el tamaño del archivo. Ah, ¿necesitas ampliar una foto pequeña sin perder calidad? Considere usar Letsenhance.io.
Estas optimizaciones hasta ahora cubren solo lo básico. Addy Osmani ha publicado una guía muy detallada sobre la optimización esencial de imágenes que profundiza en los detalles de la compresión de imágenes y la gestión del color. Por ejemplo, podría desenfocar partes innecesarias de la imagen (aplicándoles un filtro de desenfoque gaussiano) para reducir el tamaño del archivo y, eventualmente, incluso podría comenzar a eliminar colores o convertir la imagen en blanco y negro para reducir aún más el tamaño. . Para las imágenes de fondo, exportar fotos de Photoshop con una calidad del 0 al 10 % también puede ser absolutamente aceptable.
En Smashing Magazine, usamos el sufijo
-opt
para nombres de imágenes, por ejemplo,brotli-compression-opt.png
; cada vez que una imagen contiene ese sufijo, todos en el equipo saben que la imagen ya ha sido optimizada.Ah, y no use JPEG-XR en la web: "el procesamiento de decodificación de JPEG-XR del lado del software en la CPU anula e incluso supera el impacto potencialmente positivo del ahorro de tamaño de bytes, especialmente en el contexto de SPA" (no mezclarse con Cloudinary/Google's JPEG XL).
- ¿Los videos están correctamente optimizados?
Cubrimos las imágenes hasta ahora, pero hemos evitado una conversación sobre buenos GIF. A pesar de nuestro amor por los GIF, es realmente el momento de abandonarlos para siempre (al menos en nuestros sitios web y aplicaciones). En lugar de cargar GIF animados pesados que afectan tanto el rendimiento de la representación como el ancho de banda, es una buena idea cambiar a WebP animado (con GIF como alternativa) o reemplazarlos con videos HTML5 en bucle.A diferencia de las imágenes, los navegadores no precargan el contenido de
<video>
, pero los videos HTML5 tienden a ser mucho más livianos y pequeños que los GIF. ¿No es una opción? Bueno, al menos podemos agregar compresión con pérdida a los GIF con Lossy GIF, gifsicle o giflossy.Las pruebas realizadas por Colin Bendell muestran que los videos en línea dentro de las etiquetas
img
en Safari Technology Preview se muestran al menos 20 veces más rápido y se decodifican 7 veces más rápido que el equivalente GIF, además de tener una fracción del tamaño del archivo. Sin embargo, no es compatible con otros navegadores.En la tierra de las buenas noticias, los formatos de video han avanzado enormemente a lo largo de los años. Durante mucho tiempo, esperábamos que WebM se convirtiera en el formato para gobernarlos a todos, y WebP (que es básicamente una imagen fija dentro del contenedor de video WebM) se convertirá en un reemplazo para los formatos de imagen fechados. De hecho, Safari ahora es compatible con WebP, pero a pesar de que WebP y WebM obtuvieron soporte en estos días, el avance realmente no sucedió.
Aún así, podríamos usar WebM para la mayoría de los navegadores modernos:
<!-- By Houssein Djirdeh. https://web.dev/replace-gifs-with-videos/ --> <!-- A common scenartio: MP4 with a WEBM fallback. --> <video autoplay loop muted playsinline> <source src="my-animation.webm" type="video/webm"> <source src="my-animation.mp4" type="video/mp4"> </video>
Pero tal vez podríamos revisarlo por completo. En 2018, Alliance of Open Media lanzó un nuevo formato de video prometedor llamado AV1 . AV1 tiene una compresión similar al códec H.265 (la evolución de H.264) pero a diferencia de este último, AV1 es gratuito. El precio de la licencia H.265 empujó a los proveedores de navegadores a adoptar un AV1 con un rendimiento comparable: AV1 (al igual que H.265) se comprime el doble de bien que WebM .
De hecho, Apple actualmente usa el formato HEIF y HEVC (H.265), y todas las fotos y videos en el último iOS se guardan en estos formatos, no en JPEG. Si bien HEIF y HEVC (H.265) no están correctamente expuestos a la web (¿todavía?), AV1 sí lo está, y está ganando compatibilidad con los navegadores. Por lo tanto, agregar la fuente
AV1
en su etiqueta<video>
es razonable, ya que todos los proveedores de navegadores parecen estar de acuerdo.Por ahora, la codificación más utilizada y admitida es H.264, proporcionada por archivos MP4, por lo tanto, antes de entregar el archivo, asegúrese de que sus MP4 se procesen con una codificación multipaso, borrosa con el efecto frei0r iirblur (si corresponde) y Los metadatos de moov atom se mueven al encabezado del archivo, mientras que su servidor acepta el servicio de bytes. Boris Schapira proporciona instrucciones exactas para que FFmpeg optimice los videos al máximo. Por supuesto, proporcionar el formato WebM como alternativa también ayudaría.
¿Necesita comenzar a renderizar videos más rápido pero los archivos de video aún son demasiado grandes ? Por ejemplo, ¿siempre que tenga un video de fondo grande en una página de destino? Una técnica común que se usa es mostrar el primer cuadro primero como una imagen fija, o mostrar un segmento de bucle corto muy optimizado que podría interpretarse como parte del video y luego, cuando el video esté lo suficientemente almacenado en el búfer, comience a reproducirse. el vídeo real. Doug Sillars tiene una guía escrita detallada para el rendimiento de video de fondo que podría ser útil en ese caso. ( ¡Gracias, Guy Podjarny! ).
Para el escenario anterior, es posible que desee proporcionar imágenes de póster receptivas . De forma predeterminada, los elementos de
video
solo permiten una imagen como póster, lo que no es necesariamente óptimo. Podemos usar Responsive Video Poster, una biblioteca de JavaScript que le permite usar diferentes imágenes de póster para diferentes pantallas, al tiempo que agrega una superposición de transición y un control de estilo completo de los marcadores de posición de video.La investigación muestra que la calidad de la transmisión de video afecta el comportamiento del espectador. De hecho, los espectadores comienzan a abandonar el video si el retraso en el inicio supera los 2 segundos. Más allá de ese punto, un aumento de 1 segundo en la demora da como resultado un aumento de aproximadamente el 5,8 % en la tasa de abandono. Por lo tanto, no sorprende que la mediana del tiempo de inicio del video sea de 12,8 s, con un 40 % de videos que tienen al menos 1 detención y un 20 % de al menos 2 s de reproducción de video detenida. De hecho, las paradas de video son inevitables en 3G ya que los videos se reproducen más rápido de lo que la red puede proporcionar contenido.
Entonces, ¿cuál es la solución? Por lo general, los dispositivos de pantalla pequeña no pueden manejar los 720p y 1080p que estamos sirviendo en el escritorio. Según Doug Sillars, podemos crear versiones más pequeñas de nuestros videos y usar Javascript para detectar la fuente en pantallas más pequeñas para garantizar una reproducción rápida y fluida en estos dispositivos. Alternativamente, podemos usar la transmisión de video. Las transmisiones de video HLS entregarán un video de tamaño adecuado al dispositivo, lo que elimina la necesidad de crear diferentes videos para diferentes pantallas. También negociará la velocidad de la red y adaptará la tasa de bits del video a la velocidad de la red que está utilizando.
Para evitar el desperdicio de ancho de banda, solo podríamos agregar la fuente de video para dispositivos que realmente puedan reproducir bien el video. Alternativamente, podemos eliminar el atributo de
autoplay
de la etiqueta devideo
por completo y usar JavaScript para insertarautoplay
para pantallas más grandes. Además, debemos agregarpreload="none"
en elvideo
para decirle al navegador que no descargue ninguno de los archivos de video hasta que realmente necesite el archivo:<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>
Entonces podemos apuntar específicamente a los navegadores que realmente son compatibles con AV1:
<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08"> <source src="video.hevc.mp4" type="video/mp4; codecs=hevc"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>
Entonces podríamos volver a agregar la
autoplay
sobre un cierto umbral (por ejemplo, 1000px):/* By Doug Sillars. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ */ <script> window.onload = addAutoplay(); var videoLocation = document.getElementById("hero-video"); function addAutoplay() { if(window.innerWidth > 1000){ videoLocation.setAttribute("autoplay",""); }; } </script>
El rendimiento de la reproducción de video es una historia en sí misma, y si desea profundizar en ella en detalle, eche un vistazo a otra serie de Doug Sillars sobre el estado actual del video y las mejores prácticas de entrega de video que incluyen detalles sobre las métricas de entrega de video. , precarga de video, compresión y transmisión. Finalmente, puede verificar qué tan lenta o rápida será su transmisión de video con Stream or Not.
- ¿Está optimizada la entrega de fuentes web?
La primera pregunta que vale la pena hacer es si podemos utilizar las fuentes del sistema de interfaz de usuario en primer lugar; solo debemos asegurarnos de verificar que aparezcan correctamente en varias plataformas. Si no es el caso, es muy probable que las fuentes web que servimos incluyan glifos y características y pesos adicionales que no se están utilizando. Podemos pedirle a nuestra fundición tipográfica que cree subconjuntos de fuentes web o, si usamos fuentes de código abierto, subconjuntos por nuestra cuenta con Glyphhanger o Fontsquirrel. Incluso podemos automatizar todo nuestro flujo de trabajo con la subfuente de Peter Muller, una herramienta de línea de comandos que analiza estáticamente su página para generar los subconjuntos de fuentes web más óptimos y luego inyectarlos en nuestras páginas.La compatibilidad con WOFF2 es excelente, y podemos usar WOFF como respaldo para los navegadores que no lo admiten, o quizás los navegadores heredados podrían recibir fuentes del sistema. Hay muchas, muchas, muchas opciones para la carga de fuentes web, y podemos elegir una de las estrategias de la "Guía completa de estrategias de carga de fuentes" de Zach Leatherman (fragmentos de código también disponibles como recetas de carga de fuentes web).
Probablemente, las mejores opciones a considerar hoy en día son Critical FOFT con
preload
y el método "The Compromise". Ambos usan un renderizado de dos etapas para entregar fuentes web en pasos: primero se requiere un pequeño supersubconjunto para renderizar la página de forma rápida y precisa con la fuente web, y luego cargar el resto de la familia de forma asíncrona. La diferencia es que la técnica "The Compromise" carga el polyfill de forma asincrónica solo si los eventos de carga de fuentes no son compatibles, por lo que no necesita cargar el polyfill de forma predeterminada. ¿Necesitas una victoria rápida? Zach Leatherman tiene un tutorial rápido de 23 minutos y un estudio de caso para ordenar sus fuentes.En general, podría ser una buena idea usar la sugerencia de recursos de
preload
para precargar las fuentes, pero en su marcado incluya las sugerencias después del enlace a CSS y JavaScript críticos. Con lapreload
, hay un rompecabezas de prioridades, así que considere inyectar elementosrel="preload"
en el DOM justo antes de los scripts de bloqueo externos. Según Andy Davies, "los recursos inyectados mediante un script se ocultan del navegador hasta que se ejecuta el script, y podemos usar este comportamiento para demorar cuando el navegador descubre la sugerencia depreload
". De lo contrario, la carga de fuentes le costará en el primer tiempo de renderizado.Es una buena idea ser selectivo y elegir los archivos que más importan, por ejemplo, los que son críticos para la representación o que le ayudarían a evitar reflujos de texto visibles y perturbadores. En general, Zach aconseja precargar una o dos fuentes de cada familia ; también tiene sentido retrasar la carga de algunas fuentes si son menos críticas.
Se ha vuelto bastante común usar el valor
local()
(que se refiere a una fuente local por su nombre) al definir unafont-family
de fuentes en la regla@font-face
:/* Warning! Not a good idea! */ @font-face { font-family: Open Sans; src: local('Open Sans Regular'), local('OpenSans-Regular'), url('opensans.woff2') format ('woff2'), url('opensans.woff') format('woff'); }
La idea es razonable: algunas fuentes populares de código abierto como Open Sans vienen preinstaladas con algunos controladores o aplicaciones, por lo que si la fuente está disponible localmente, el navegador no necesita descargar la fuente web y puede mostrar la fuente local. fuente inmediatamente. Como señaló Bram Stein, "aunque una fuente local coincida con el nombre de una fuente web, lo más probable es que no sea la misma fuente . Muchas fuentes web difieren de su versión de "escritorio". volviendo a otras fuentes, las características de OpenType pueden faltar por completo o la altura de la línea puede ser diferente".
Además, a medida que los tipos de letra evolucionan con el tiempo, la versión instalada localmente puede ser muy diferente de la fuente web, con caracteres que se ven muy diferentes. Entonces, según Bram, es mejor nunca mezclar fuentes instaladas localmente y fuentes web en las reglas
@font-face
. Google Fonts hizo lo mismo al deshabilitarlocal()
en los resultados de CSS para todos los usuarios, excepto las solicitudes de Android para Roboto.A nadie le gusta esperar a que se muestre el contenido. Con el descriptor CSS
font-display
, podemos controlar el comportamiento de carga de la fuente y permitir que el contenido se pueda leer inmediatamente (confont-display: optional
) o casi inmediatamente (con un tiempo de espera de 3 s, siempre que la fuente se descargue correctamente, confont-display: swap
). (Bueno, es un poco más complicado que eso).Sin embargo, si desea minimizar el impacto de los reflujos de texto, podemos usar la API de carga de fuentes (compatible con todos los navegadores modernos). Específicamente, eso significa que para cada fuente, crearíamos un objeto
FontFace
, luego intentaríamos obtenerlos todos y solo luego los aplicaríamos a la página. De esta manera, agrupamos todos los repintados cargando todas las fuentes de forma asincrónica y luego cambiamos de las fuentes alternativas a la fuente web exactamente una vez. Eche un vistazo a la explicación de Zach, a partir de las 32:15, y al fragmento de código):/* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));
/* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));
Para iniciar una recuperación muy temprana de las fuentes con la API de carga de fuentes en uso, Adrian Bece sugiere agregar un espacio sin interrupciones
nbsp;
en la parte superior delbody
y ocultarlo visualmente conaria-visibility: hidden
y una clase.hidden
:<body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>
<body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>
Esto va junto con CSS que tiene diferentes familias de fuentes declaradas para diferentes estados de carga, con el cambio activado por la API de carga de fuentes una vez que las fuentes se han cargado correctamente:
body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }
body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }
Si alguna vez se preguntó por qué, a pesar de todas sus optimizaciones, Lighthouse aún sugiere eliminar los recursos de bloqueo de procesamiento (fuentes), en el mismo artículo, Adrian Bece proporciona algunas técnicas para hacer feliz a Lighthouse, junto con Gatsby Omni Font Loader, una fuente asincrónica de alto rendimiento. Carga y complemento de manejo de Flash Of Unstyled Text (FOUT) para Gatsby.
Ahora, muchos de nosotros podríamos estar usando un CDN o un host de terceros para cargar fuentes web. En general, siempre es mejor autoalojar todos sus recursos estáticos si puede, así que considere usar google-webfonts-helper, una forma sencilla de autohospedar Google Fonts. Y si no es posible, quizás pueda enviar los archivos de fuentes de Google a través del origen de la página.
Sin embargo, vale la pena señalar que Google está trabajando bastante desde el primer momento, por lo que un servidor podría necesitar algunos ajustes para evitar retrasos ( ¡gracias, Barry! )
Esto es bastante importante, especialmente porque desde Chrome v86 (lanzado en octubre de 2020), los recursos entre sitios, como las fuentes, ya no se pueden compartir en la misma CDN, debido a la memoria caché del navegador dividida. Este comportamiento fue predeterminado en Safari durante años.
Pero si no es posible en absoluto, hay una manera de obtener las fuentes de Google más rápidas posibles con el fragmento de código de Harry Roberts:
<!-- By Harry Roberts. https://csswizardry.com/2020/05/the-fastest-google-fonts/ - 1. Preemptively warm up the fonts' origin. - 2. Initiate a high-priority, asynchronous fetch for the CSS file. Works in - most modern browsers. - 3. Initiate a low-priority, asynchronous fetch that gets applied to the page - only after it's arrived. Works in all browsers with JavaScript enabled. - 4. In the unlikely event that a visitor has intentionally disabled - JavaScript, fall back to the original method. The good news is that, - although this is a render-blocking request, it can still make use of the - preconnect which makes it marginally faster than the default. --> <!-- [1] --> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <!-- [2] --> <link rel="preload" as="style" href="$CSS&display=swap" /> <!-- [3] --> <link rel="stylesheet" href="$CSS&display=swap" media="print" onload="this.media='all'" /> <!-- [4] --> <noscript> <link rel="stylesheet" href="$CSS&display=swap" /> </noscript>
La estrategia de Harry es calentar primero de forma preventiva el origen de las fuentes. Luego iniciamos una búsqueda asincrónica de alta prioridad para el archivo CSS. Luego, iniciamos una recuperación asincrónica de baja prioridad que se aplica a la página solo después de que llega (con un truco de hoja de estilo de impresión). Finalmente, si JavaScript no es compatible, recurrimos al método original.
Ah, hablando de Google Fonts: puede reducir hasta el 90 % del tamaño de las solicitudes de Google Fonts declarando solo los caracteres que necesita con
&text
. Además, la compatibilidad con la visualización de fuentes también se agregó recientemente a Google Fonts, por lo que podemos usarla de forma inmediata.Sin embargo, una breve advertencia. Si usa
font-display: optional
, podría ser subóptimo usar también lapreload
, ya que activará esa solicitud de fuente web antes (causando congestión en la red si tiene otros recursos de ruta crítica que deben recuperarse). Utilice lapreconnect
para solicitudes de fuentes de origen cruzado más rápidas, pero tenga cuidado con lapreload
, ya que la precarga de fuentes de un origen diferente provocará conflictos en la red. Todas estas técnicas están cubiertas en las recetas de carga de fuentes web de Zach.Por otro lado, podría ser una buena idea excluirse de las fuentes web (o al menos el renderizado de segunda etapa) si el usuario ha habilitado Reducir movimiento en las preferencias de accesibilidad o ha optado por el Modo de ahorro de datos (consulte el encabezado
Save-Data
) , o cuando el usuario tiene una conectividad lenta (a través de la API de información de red).También podemos usar la consulta de medios CSS
prefers-reduced-data
para no definir declaraciones de fuente si el usuario ha optado por el modo de ahorro de datos (también hay otros casos de uso). La consulta de medios básicamente expondría si el encabezado de la solicitudSave-Data
de la extensión HTTP Client Hint está activado/desactivado para permitir el uso con CSS. Actualmente solo se admite en Chrome y Edge detrás de una bandera.¿Métrica? Para medir el rendimiento de carga de la fuente web, considere la métrica Todo el texto visible (el momento en que todas las fuentes se han cargado y todo el contenido se muestra en las fuentes web), el Tiempo para la cursiva real y el Conteo de flujo de fuente web después del primer renderizado. Obviamente, cuanto más bajas sean ambas métricas, mejor será el rendimiento.
¿Qué pasa con las fuentes variables , podrías preguntar? Es importante tener en cuenta que las fuentes variables pueden requerir una consideración de rendimiento significativa. Nos brindan un espacio de diseño mucho más amplio para las opciones tipográficas, pero tiene el costo de una sola solicitud en serie en lugar de varias solicitudes de archivos individuales.
Si bien las fuentes variables reducen drásticamente el tamaño de archivo combinado general de los archivos de fuentes, esa única solicitud puede ser lenta y bloquear la representación de todo el contenido de una página. Por lo tanto, subdividir y dividir la fuente en conjuntos de caracteres sigue siendo importante. Sin embargo, en el lado bueno, con una fuente variable en su lugar, obtendremos exactamente un reflujo por defecto, por lo que no se requerirá JavaScript para agrupar repintados.
Ahora, ¿qué haría entonces una estrategia de carga de fuentes web a prueba de balas ? Crea subconjuntos de fuentes y prepáralas para el renderizado en 2 etapas, decláralas con un descriptor
font-display
, usa la API de carga de fuentes para agrupar repintados y almacenar fuentes en la memoria caché de un trabajador de servicio persistente. En la primera visita, inyecte la precarga de scripts justo antes de los scripts externos de bloqueo. Si es necesario, puede recurrir al Font Face Observer de Bram Stein. Y si está interesado en medir el rendimiento de la carga de fuentes, Andreas Marschke explora el seguimiento del rendimiento con Font API y UserTiming API.Por último, no se olvide de incluir
unicode-range
para dividir una fuente grande en fuentes más pequeñas específicas del idioma, y use el comparador de estilo de fuente de Monica Dinculescu para minimizar un cambio discordante en el diseño, debido a las discrepancias de tamaño entre el respaldo y el fuentes webAlternativamente, para emular una fuente web para una fuente alternativa, podemos usar los descriptores @font-face para anular las métricas de fuente (demostración, habilitado en Chrome 87). (Tenga en cuenta que los ajustes son complicados con pilas de fuentes complicadas).
¿El futuro parece brillante? Con el enriquecimiento progresivo de la fuente, eventualmente podríamos "descargar solo la parte requerida de la fuente en cualquier página dada, y para las solicitudes posteriores de esa fuente para 'parchar' dinámicamente la descarga original con conjuntos adicionales de glifos según sea necesario en la página sucesiva". puntos de vista", como explica Jason Pamental. La demostración de transferencia incremental ya está disponible y está en proceso.
Tabla de contenido
- Preparándose: planificación y métricas
- Establecer metas realistas
- Definición del entorno
- Optimizaciones de activos
- Optimizaciones de compilación
- Optimizaciones de entrega
- Redes, HTTP/2, HTTP/3
- Pruebas y monitoreo
- Triunfos rápidos
- Todo en una página
- Descargar la lista de verificación (PDF, Apple Pages, MS Word)
- Suscríbase a nuestro boletín de correo electrónico para no perderse las próximas guías.