Estoy tratando de cargar mis imágenes con un efecto de desvanecimiento que se activará una vez que se cargue la imagen. Me di cuenta de que onload funciona correctamente en Chrome, pero en Firefox o Safari se llama unos cientos de milisegundos antes de que se procese la imagen, por lo que se omitirá cualquier animación por debajo de esa duración.
He estado leyendo otras preguntas, como:
evento image.onload y caché del navegador : no es útil, ya que no es un problema de caché, ya que la imagen siempre es nueva;
evento de carga en las etiquetas <img> que se disparan prematuramente en Firefox, no en otros navegadores : en esta pregunta se señala que Firefox tenía un problema con la carga, que se activaba al inicio de la carga en lugar de al final de la carga; pero en nuestro caso onload se dispara correctamente al final de la carga de la imagen; es la imagen lo que se representa algunos ms después de que finaliza la carga.
Aquí creé un fragmento que demuestra el problema usando imágenes pesadas de Picsum —3000 x 3000—. Al abrir esta pregunta en Chrome y ejecutar este fragmento, al cargar la imagen se desvanece; pero al abrir esta misma pregunta en Firefox o Safari, la imagen se muestra sin aparecer.
const imgElement = new Image(); const rootElement = document.getElementById("root"); rootElement.append(imgElement); imgElement.className = "image"; imgElement.src = "https://picsum.photos/3000/3000"; imgElement.onload = function () { imgElement.classList.add("loaded"); }; .image { border: 2px solid gray; max-width: 100%; opacity: 0; transition: opacity 0.3s ease; } .image.loaded { opacity: 1; } <div id="root"></div>¡Cualquier idea será bienvenida!
Sí, el evento de carga corresponde al momento en que se obtuvo el recurso de red y cuando el navegador se aseguró de que podrá leerlo sin problemas.
Ahí es cuando Firefox y Safari activan el evento, según las especificaciones.
Chrome actualmente hace más trabajo antes de activar este evento, ya que esperarán hasta que se complete la decodificación completa.
Entonces, como adivinaste correctamente, Safari y Firefox primero renderizarán el elemento <img> vacío, aplicarán la transición en esa imagen vacía y luego solo renderizarán la imagen final.
Para superar este problema, puede usar una adición relativamente reciente a las especificaciones de HTML: HTMLImageElement#decode() . Este método devolverá una Promesa, resolviendo cuando la parte de decodificación se haya completado por completo.
const imgElement = new Image(); const rootElement = document.getElementById("root"); rootElement.append(imgElement); imgElement.className = "image"; imgElement.src = "https://picsum.photos/3000/3000"; imgElement.decode().then(()=>{ imgElement.classList.add("loaded"); }); .image { border: 2px solid gray; max-width: 100%; opacity: 0; transition: opacity 0.3s ease; } .image.loaded { opacity: 1; } <div id="root"></div> Ps: para aquellos que necesitan admitir navegadores más antiguos que aún no decode() , hay una manera de forzar la decodificación sincrónicamente .
Idealmente,
window.load antes de agregar la etiqueta de imagen al DOMimgElement onload configurarse antes de cargar o imgElement al DOMCon estos cambios y haciendo que la duración de la animación pase de 0,3 s a 3 s (para facilitar la observación), el comportamiento es uniforme en todos los navegadores.
window.addEventListener("load", () => { const imgElement = new Image(); const rootElement = document.getElementById("root"); imgElement.onload = function () { imgElement.classList.add("loaded"); }; rootElement.append(imgElement); imgElement.className = "image"; imgElement.src = "https://picsum.photos/3000/3000"; }); .image { border: 2px solid gray; max-width: 100%; opacity: 0; transition: opacity 3s ease; } .image.loaded { opacity: 1; } <div id="root"></div>