w3schools property img attribute javascript css sass

javascript - property - Precarga de imágenes de fondo



title label html (4)

Estoy construyendo una página que recorre 3 fondos diferentes, cambiando cada 750 ms. Para hacer esto, agrego una clase al cuerpo con la imagen de fondo relevante, cambiando con JS. Para el primer ciclo, parpadean porque la imagen tiene que cargarse, por lo que no está allí instantáneamente. Por lo tanto, ¿hay algún método que pueda usar para precargar las imágenes?

CSS:

&.backgrounds{ background-position: center bottom; background-repeat: no-repeat; background-size: 130%; &.freddy{ background-image: url(/img/illustrations/snapchat/snapchat_holding_page_freddy.jpg); } &.irene{ background-image: url(/img/illustrations/snapchat/snapchat_holding_page_irene.jpg); } &.joe{ background-image: url(/img/illustrations/snapchat/snapchat_holding_page_joe.jpg); } }

JS:

setInterval(function() { if ( $(''.backgrounds'').hasClass(''freddy'') ){ $(''.backgrounds'').removeClass(''freddy'').addClass(''irene''); } else if ( $(''.backgrounds'').hasClass(''irene'') ){ $(''.backgrounds'').removeClass(''irene'').addClass(''joe''); } else if ( $(''.backgrounds'').hasClass(''joe'') ){ $(''.backgrounds'').removeClass(''joe'').addClass(''freddy''); } }, 750);


Idea interesante.

¿Podría potencialmente cargarlos en segundo plano, así como:

<div class="hidden-images"> <img src="img1.jpg" /> <img src="img2.jpg" /> <img src="img3.jpg" /> </div>

Luego en CSS

.hidden-images { position: relative; z-index: 1; }

Entonces, en lo que sea que tipo de contenedor principal div es, dale una cachetada a lo siguiente?

.main-container { position: relative; z-index: 2; // Or higher, whatever is needed }


Puedes cargarlos en javascript. Me gusta:

(new Image()).src = url1; (new Image()).src = url2; (new Image()).src = url3;

Cambia el "url1", "url2", "url3" con tus propias URL de imagen. El navegador cargará la imagen pero no será visible en ningún lado.


También puede hacer esto con diferentes estructuras html y css como esta.

html

<div class="backgrounds"> <div class="background freddy"></div> </div>

css

.backgrounds{ background-color: transparent; background-position: center bottom; background-repeat: no-repeat; background-size: 130%; height: 250px; width; 100%; } .backgrounds .freddy{ height: 100%; width: 100%; background-image: url(''http://adrianweb.net/includes/images/hero.jpg''); } .backgrounds .irene{ height: 100%; width: 100%; background-image: url(''http://adrianweb.net/includes/images/projects-blur.png''); } .backgrounds .joe{ height: 100%; width: 100%; background-image: url(''http://adrianweb.net/includes/images/contacts-blur.png''); }

JS

$(document).ready(function(){ setInterval(function() { if ( $(''.background'').hasClass(''freddy'') ){ $(''.background'').removeClass(''freddy'').addClass(''irene''); } else if ( $(''.background'').hasClass(''irene'') ){ $(''.background'').removeClass(''irene'').addClass(''joe''); } else if ( $(''.background'').hasClass(''joe'') ){ $(''.background'').removeClass(''joe'').addClass(''freddy''); } }, 750); });

Tal vez pueda agregar transición / animación para que se vea desvanecerse y desaparecer.

Códepen de muestra a continuación:

http://codepen.io/adrianrios/pen/yMEpEv


Haría algo así. loadImages devuelve una Promesa que se resolverá una vez que se carguen todas las imágenes. El .then conectado a él llama cycleImages , que inicia el intervalo. Ya que necesitarás las URL en JS para hacer la precarga, en lugar de cambiar de clase, estoy manipulando directamente la background-image , de esa manera puedes eliminar las URL de imagen del CSS y guardar algunos bytes redundantes. Esto también facilita la expansión de la lista de imágenes en el futuro, solo necesita agregar un elemento a la matriz de imágenes en lugar de mantener una declaración if complicada.

function loadImages (images) { // each image will be loaded by this function. // it returns a Promise that will resolve once // the image has finished loading let loader = function (src) { return new Promise(function (resolve, reject) { let img = new Image(); img.onload = function () { // resolve the promise with our url so it is // returned in the result of Promise.all resolve(src); }; img.onerror = function (err) { reject(err); }; img.src = src; }); }; // create an image loader for each url let loaders = []; images.forEach(function (image) { loaders.push(loader(image)); }); // Promise.all will return a promise that will resolve once all of of our // image loader promises resolve return Promise.all(loaders); } // the images we are going to display let myImages = [ ''http://www.gifpng.com/400x200'', ''http://www.gifpng.com/400x200/ffffff/000000'', ''http://www.gifpng.com/400x200/000000/ffffff'' ]; // $(document).ready(fn) is deprecated, // use the $(fn) form instead $(function() { // after the images are loaded this will be called with an array of the loaded images function cycleImages (images) { let index = 0; setInterval(function() { // since we need an array of the image names to preload them anyway, // just load them via JS instead of class switching so you can cut them // out of the CSS and save some space by not being redundant $(''#backgrounds'').css(''backgroundImage'', ''url("'' + images[index] + ''")''); // increment, roll over to 0 if at length after increment index = (index + 1) % images.length; }, 750); } // load the images and start cycling through them after they are loaded loadImages(myImages).then(cycleImages).catch(function (err) { console.error(err); }); });

#backgrounds { height: 200px; width: 400px; border: 1px solid #000; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="backgrounds"></div>

Editar: teniendo en cuenta solo los comentarios de un alumno , aquí hay una versión que solo cambiará la imagen una vez cargada, pero lo hará de inmediato si está cargada. También omite las imágenes que no se cargaron. Dado que cycleImages ya no se llama mediante .then , también lo cambié para que acepte un elemento de destino (como un objeto jQuery) junto con una matriz de promesas de imágenes. De esta forma, puede usarlo fácilmente en múltiples lugares de una página con diferentes conjuntos de imágenes, si así lo desea.

function loadImages (images) { // each image will be loaded by this function. // it returns a Promise that will resolve once // the image has finished loading let loader = function (src) { return new Promise(function (resolve, reject) { let img = new Image(); img.onload = function () { // resolve the promise with our url resolve(src); }; img.onerror = function (err) { reject(err); }; img.src = src; }); }; // return an array of image-loading promises return images.map(function (image) { return loader(image); }); } // the images we are going to display let myImages = [ ''http://www.gifpng.com/400x200'', ''http://www.invalid-domain-name.foo/this-url-certainly-does-not-exist.jpg'', ''http://www.gifpng.com/400x200/ffffff/000000'', ''http://www.gifpng.com/400x200/000000/ffffff'' ]; // $(document).ready(fn) is deprecated, // use the $(fn) form instead $(function() { // this receives an array of the promises for each image function cycleImages ($target, images) { let index = 0, interval = 750; // how many ms to wait before attempting to switch images function nextImage () { // p is the promise for the current image let p = images[index], next = function (wait) { // increment our counter and wait to display the next one index = (index + 1) % images.length; setTimeout(nextImage, wait); }; // wait for this image to load or fail to load p.then(function (src) { // it loaded, display it $target.css(''backgroundImage'', ''url("'' + src + ''")''); next(interval); }).catch(function (err) { // this one failed to load, skip it next(0); }); } // start cycling nextImage(); } // load the images and start cycling through them as they are loaded cycleImages($(''#backgrounds''), loadImages(myImages)); });

#backgrounds { height: 200px; width: 400px; border: 1px solid #000; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="backgrounds"></div>

En lugar de codificar el intervalo entre cambios de imágenes, también podría pasarlo como un parámetro. En ese momento, sin embargo, lo refactorizaría para usar un objeto de configuración para pasar todo menos la matriz de promesa de imagen: cycleImages(myImages, {target: $(''#backgrounds''), interval: 1000});