Diferir imágenes fuera de pantalla en móviles

Diferir imágenes fuera de pantalla en móviles

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-01-23

Diferimiento de Imágenes en Móviles: el estándar

El rendimiento móvil a menudo se ve limitado por la latencia de red (RTT) y la disponibilidad de CPU del hilo principal. Diferir las imágenes fuera de pantalla en móviles aborda ambos problemas al prevenir la contención de ancho de banda en la ruta crítica de renderizado y distribuir los costos de decodificación de imágenes a lo largo de la duración de la sesión.

Este documento explica cómo diferir imágenes en móviles de manera efectiva, cuándo usarlo y aborda las restricciones mecánicas específicas de los viewports móviles.

priority waterfall web dev example

1. Diferir imágenes fuera de pantalla en móviles: lazy loading nativo

Cuando un navegador carga una página, abre un número limitado de conexiones paralelas (dependiendo de muchos factores pero 6 por dominio es un promedio común). Si estas conexiones se utilizan para descargar imágenes fuera de pantalla (por ejemplo, un logo de pie de página o diapositiva de carrusel), la descarga de recursos críticos (típicamente la imagen LCP, scripts importantes y fuentes competirán por espacios y ancho de banda). Este fenómeno, conocido como Contención de Red, degrada directamente los Core Web Vitals.

Al diferir imágenes fuera de pantalla usando el atributo nativo loading, podemos priorizar recursos importantes y optimizar la Ruta Crítica de Renderizado. El navegador obtiene solo lo que es inmediatamente visible, reservando ancho de banda para los activos que impactan estrictamente el First Contentful Paint (FCP) y el Largest Contentful Paint (LCP). El método nativo de lazy loading descarga esta lógica de priorización a ellos mucho más rápido mecanismo interno del navegador, eliminando la necesidad de bibliotecas JavaScript antiguas y lentas.

Implementación

Para todas las imágenes debajo del viewport inicial ("el pliegue") añade el atributo loading="lazy".

<!-- Imagen Diferida Estándar -->
<img src="product-detail.jpg"
     
     alt="Vista lateral del chasis"
     width="800"
     height="600"
     decoding="async">

Cómo funciona el lazy loading en móviles: La Heurística del Navegador

El lazy loading nativo es superior a las soluciones JavaScript porque el navegador ajusta el umbral de carga (cuando se activa la descarga de una imagen) basándose en el Effective Connection Type (ECT).

  • En 4G/WiFi: El motor Blink (Chrome/Edge) emplea un umbral conservador (por ejemplo, 1250px). Asume baja latencia y obtiene la imagen solo cuando el usuario está relativamente cerca del viewport.
  • En 3G/Slow-2G: El umbral se expande (por ejemplo, 2500px). El navegador inicia la solicitud mucho antes en relación con la posición de desplazamiento para compensar los tiempos de ida y vuelta altos, asegurando que la imagen esté lista antes de que el usuario la desplace a la vista.

Excepción Crítica: El Candidato LCP

Una regresión de rendimiento común ocurre cuando los desarrolladores aplican loading="lazy" al elemento Largest Contentful Paint (LCP) (típicamente la imagen hero). Esto retrasa la obtención hasta que el diseño está completo.

Estrategia LCP Correcta: La imagen LCP debe cargarse con eager y priorizarse.

<!-- Imagen Hero: Eager y Priorizada -->
<img src="hero.jpg"
     alt="Colección de Verano"
     width="1200"
     height="800"
     
     > 

2. Complejidades móviles: Viewport y Táctil

Los viewports móviles introducen desafíos de renderizado específicos que la implementación nativa maneja de manera más robusta que las soluciones basadas en scripts.

  • El Viewport: El área rectangular visible de la ventana del navegador. En móviles, esto es dinámico; cambia de dimensiones según la orientación del dispositivo (vertical vs. horizontal) y el estado del chrome del navegador (barras de URL retrayéndose).
  • El Pliegue: El borde inferior exacto del viewport. Es el umbral que separa el contenido visible del contenido fuera de pantalla.
  • Encima del Pliegue: Cualquier contenido visible inmediatamente al cargar la página sin desplazarse. Las imágenes aquí son a menudo críticas y casi nunca deberían cargarse con lazy-load.
  • Debajo del Pliegue: Cualquier contenido ubicado verticalmente más allá del pliegue. Este contenido es No Crítico y debe diferirse hasta que el usuario se desplace cerca de él.

above and below the mobile fold 22 01 26

El Viewport Dinámico

En los navegadores móviles, la altura del viewport (vh) es fluida. Cuando el usuario inicia un desplazamiento táctil, la barra de URL y los controles de navegación a menudo se retraen, cambiando el tamaño del área visible.

Las bibliotecas de diferimiento de imágenes basadas en JavaScript usualmente calculan la altura del viewport (window.innerHeight) solo una vez al inicio de la carga de la página.  Cuando los navegadores móviles redimensionan dinámicamente el área visible ocultando la barra de URL durante un desplazamiento, los métodos Java Script continúan usando el valor de altura antiguo y más pequeño. Esto causaba que las imágenes permanecieran sin cargar incluso cuando físicamente entraban en el área de viewport expandida causando una mala UX para los visitantes.

El Manejo Nativo soluciona este problema ya que el motor de diseño interno del navegador rastrea el viewport visual automáticamente, asegurando que los activadores se disparen independientemente de cualquier cambio de tamaño del viewport.

3. Decodificación de Imágenes Móviles y Limitación de CPU

Los dispositivos móviles tienen CPU limitada y la decodificación de imágenes en móviles puede ser relativamente lenta y costosa. Convertir un JPEG en un mapa de bits requiere muchos ciclos de CPU. En un procesador móvil, decodificar una secuencia de imágenes más grandes puede bloquear el hilo principal durante 50ms–100ms cada una, causando latencia de entrada.

La Solución: content-visibility

Para resolver esto, podemos usar la propiedad CSS y valor content-visibility: auto. Esta propiedad actúa como un estándar para "Lazy Rendering." Instruye al navegador a omitir las fases de diseño y pintura para elementos fuera de pantalla por completo. El elemento existe en el DOM, pero no existe en el Árbol de Renderizado hasta que se aproxima al viewport.

Debido a que esta optimización funciona omitiendo el renderizado del subárbol de un elemento, no puedes aplicarlo directamente a una etiqueta <img> (que no tiene subárbol). Debes aplicar conten-visibility al contenedor del producto o tarjeta de imagen que aloja estas imágenes y su contenido

@media (max-width: 768px) {
    .image-card, .product-card {
        /* Omitir renderizado del contenedor y sus hijos */
        content-visibility: auto;
        
        /* Esencial: Previene que el contenedor colapse a 0px de altura */
        contain-intrinsic-size: auto 300px;
    }
}

Esto asegura que incluso si una imagen se descarga, el navegador no paga el costo de diseño/pintura hasta que el usuario realmente se desplace hacia ella.

4. Metodologías Heredadas: Por qué evitarlas

Antes del soporte nativo, los desarrolladores confiaban en JavaScript para el diferimiento de imágenes móviles. Estos métodos todavía se usan ampliamente pero deben considerarse como deuda técnica!

La Era del "Manejador de Scroll" (2010–2016)

Las primeras implementaciones adjuntaban escuchadores de eventos al evento de scroll.

// OBSOLETO: No usar
window.addEventListener(scroll, () => {
    images.forEach(img => {
        if (img.getBoundingClientRect().top < window.innerHeight) {
            img.src = img.dataset.src;
        }
    });
});

Bloqueo del Hilo Principal: El evento de scroll se dispara docenas de veces por segundo. Ejecutar lógica y calcular diseño (getBoundingClientRect) durante el desplazamiento activo causaba caídas de fotogramas (jank).

Thrashing de Diseño: Consultar propiedades geométricas obliga al navegador a recalcular sincrónicamente el estilo de diseño, una operación computacionalmente costosa en CPUs móviles. 

La Era IntersectionObserver (2016–2019)

La API IntersectionObserver mejoró el rendimiento al observar asincrónicamente cambios en la visibilidad de elementos. 

// OBSOLETO: Usa carga nativa donde sea posible
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            observer.unobserve(img);
        }
    });
});

Dependencia de Script: Requiere ejecución de JavaScript. Si el hilo principal está ocupado hidratando un framework (React/Vue), las imágenes permanecen sin cargar incluso si están en el viewport.

Falta de Conciencia de Red: A diferencia de la carga nativa, IntersectionObserver usa márgenes fijos (por ejemplo, rootMargin: 200px). No expande automáticamente su búfer en redes lentas, lo que lleva a "destellos blancos" para usuarios con conexiones pobres.


Your dev team is busy.

Delegate the performance architecture to a specialist. I handle the optimization track while your team ships the product.

Discuss Resource Allocation >>

  • Parallel Workflows
  • Specialized Expertise
  • Faster Delivery
Diferir imágenes fuera de pantalla en móvilesCore Web Vitals Diferir imágenes fuera de pantalla en móviles