Comment puis-je vérifier si une image d'arrière-plan est chargée?

154

Je veux définir une image d'arrière-plan sur la balise body, puis exécuter du code - comme ceci:

$('body').css('background-image','http://picture.de/image.png').load(function() {
    alert('Background image done loading');
    // This doesn't work
});

Comment puis-je m'assurer que l'image d'arrière-plan est entièrement chargée?

Peter
la source
4
Attribuez simplement la même URL à l' Image()objet qui a un onloadévénement.
Shadow Wizard est une oreille pour vous le
2
assurez-vous d'envelopper l'url css dansurl()
bluescrubbie

Réponses:

274

essaye ça:

$('<img/>').attr('src', 'http://picture.de/image.png').on('load', function() {
   $(this).remove(); // prevent memory leaks as @benweet suggested
   $('body').css('background-image', 'url(http://picture.de/image.png)');
});

cela créera une nouvelle image en mémoire et utilisera l'événement load pour détecter le chargement du src.

jcubic
la source
10
On dirait que l'image serait chargée deux fois sans raison.
HyderA
49
@gAMBOOKa Ils sont chargés une fois car ils restent dans la mémoire du navigateur. C'est la même chose, lorsque vous placez des images cachées en haut de votre page, puis que vous les définissez en CSS - les images commencent donc à être téléchargées avant le fichier css - cela s'appelle le préchargement.
jcubic
4
Je ne suis pas trop sûr, mais je pense que vous parlez de cache. Je ne pense pas qu'il existe une mémoire de navigateur où les actifs sont stockés. Si vous faites référence au cache, n'oubliez pas que vous ajoutez une requête HTTP supplémentaire et que tous les clients n'ont peut-être pas le cache activé.
HyderA
7
Entrez ceci dans n'importe quelle page contenant jquery: javascript:void($('<img/>').attr('src', 'http://farm6.static.flickr.com/5049/5220175127_5693faf952.jpg').load(function() { $('html').css('background-image', 'url(http://farm6.static.flickr.com/5049/5220175127_5693faf952.jpg)'); }))et vérifiez les requêtes HTTP dans Firebug. Si j'ai ouvert la page scintillante avec cette image ouverte dans un autre onglet, il ne fait aucune requête HTTP, affichez simplement cette image instantanément. et quand je vide le cache et l'exécute, il y avait une demande.
jcubic
26
Une comparaison entre ce test et celui-ci montre qu'il faut faire appel .remove()à $('<img/>')object pour éviter une fuite de mémoire. Vous devriez voir une consommation de mémoire stable sur le premier test et une augmentation de la mémoire sur le second. Après quelques heures de fonctionnement sur Chrome 28, le premier test prend 80 Mo et le second 270 Mo.
benweet
23

J'ai un plugin jQuery appelé waitForImagesqui peut détecter le téléchargement des images d'arrière-plan.

$('body')
  .css('background-image','url(http://picture.de/image.png)')
  .waitForImages(function() {
    alert('Background image done loading');
    // This *does* work
  }, $.noop, true);
Alex
la source
Ce plugin est également idéal pour pouvoir afficher la progression du chargement à l'aide du eachrappel.
Soviut
1
@alex, Comment dois-je vérifier chaque image d'arrière-plan pour chaque élément d'une classe? J'ai essayé mais ne semble pas le faire correctement. $ ('. user_main_photo_thumb'). waitForImages (function () {$ (this) .parents ('. photoThumbFrame'). delay (1000) .slideDown ();}, function (chargé, nombre, succès) {});
Relm
@Relm Vous ne l'utilisez pas correctement. Le deuxième rappel est par image. De plus, delay()ça ne marche pas comme ça.
alex
16

Quelque chose comme ça:

var $div = $('div'),
  bg = $div.css('background-image');
  if (bg) {
    var src = bg.replace(/(^url\()|(\)$|[\"\'])/g, ''),
      $img = $('<img>').attr('src', src).on('load', function() {
        // do something, maybe:
        $div.fadeIn();
      });
  }
});
Colin
la source
bonjour ... cela semble fonctionner, même si j'ai mis le bg.replace sur bg.replace( ... , my_src ). Mais ma question est: une fois le $ ('<img>') chargé, que se passe-t-il exactement avec ça <img>... Je veux dire que ce n'est pas vraiment réel - c'est juste un espace réservé factice, non?
dsdsdsdsd
Droite. Le <img>n'est jamais inséré dans le DOM; il est juste utilisé pour "tromper" le navigateur en chargeant le fichier image dans le cache.
Colin
utile si vous ne voulez pas appeler jQuery
vwvan
15

Il n'y a pas de callback JS pour les actifs CSS.

Adrian Pacala
la source
3
Merci pour la réponse rapide. Des idées pour une solution de contournement?
Peter
mais il existe une solution JS pour ceux qui recherchent stackoverflow.com/questions/5057990/…
godblessstrawberry
8

pure solution JS qui ajoutera un préchargeur, définira l'image d'arrière-plan, puis la configurera pour le garbage collection avec son écouteur d'événements :

Version courte:

const imageUrl = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
let bgElement = document.querySelector("body");
let preloaderImg = document.createElement("img");
preloaderImg.src = imageUrl;

preloaderImg.addEventListener('load', (event) => {
    bgElement.style.backgroundImage = `url(${imageUrl})`;
    preloaderImg = null;
});

Un peu plus longtemps avec une belle transition d'opacité:

const imageUrl = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
let bgElement = document.querySelector(".bg-lazy");
bgElement.classList.add("bg-loading");
let preloaderImg = document.createElement("img");
preloaderImg.src = imageUrl;

preloaderImg.addEventListener('load', (event) => {
  bgElement.classList.remove("bg-loading");
  bgElement.style.backgroundImage = `url(${imageUrl})`;
  preloaderImg = null;
});
.bg-lazy {
  height: 100vh;
  width: 100vw;
  transition: opacity 1s ease-out;
}

.bg-loading {
  opacity: 0;
}
<div class="bg-lazy"></div>

fraise
la source
3
Solution sous-estimée.
Tom Thomson le
1
@TomThomson merci Tom, j'ai trouvé que la transition d'image ne fonctionnait pas correctement, je l'
ai corrigée
6

Voici un petit plugin que j'ai créé pour vous permettre de faire exactement cela, il fonctionne également sur plusieurs images d'arrière-plan et plusieurs éléments:

Lire l'article:

http://catmull.uk/code-lab/background-image-loaded/

ou allez directement au code du plugin:

http://catmull.uk/downloads/bg-loaded/bg-loaded.js

Il suffit donc d'inclure le plugin, puis de l'appeler sur l'élément:

<script type="text/javascript" src="http://catmull.uk/downloads/bg-loaded/bg-loaded.js"></script>
<script type="text/javascript">
   $('body').bgLoaded();
</script>

Téléchargez évidemment le plugin et stockez-le sur votre propre hébergement.

Par défaut, il ajoute une classe supplémentaire "chargée par bg" à chaque élément correspondant une fois l'arrière-plan chargé, mais vous pouvez facilement changer cela en lui passant une fonction différente comme celle-ci:

<script type="text/javascript" src="http://catmull.uk/downloads/bg-loaded/bg-loaded.js"></script>
<script type="text/javascript">
   $('body').bgLoaded({
      afterLoaded : function() {
         alert('Background image done loading');
      }
   });
</script>

Voici un codepen démontrant qu'il fonctionne.

http://codepen.io/catmull/pen/Lfcpb

Jon Catmull
la source
3

J'ai localisé une solution qui fonctionnait mieux pour moi, et qui a l'avantage d'être utilisable avec plusieurs images (cas non illustré dans cet exemple).

D'après la réponse de @ adeneo à cette question :

Si vous avez un élément avec une image d'arrière-plan, comme ceci

<div id="test" style="background-image: url(link/to/image.png)"><div>

Vous pouvez attendre que l'arrière-plan se charge en obtenant l'URL de l'image et en l'utilisant pour un objet image en javascript avec un gestionnaire onload

var src = $('#test').css('background-image');
var url = src.match(/\((.*?)\)/)[1].replace(/('|")/g,'');

var img = new Image();
img.onload = function() {
    alert('image loaded');
}
img.src = url;
if (img.complete) img.onload();
Paperjuice
la source
2

J'ai fait un hack pur javascript pour rendre cela possible.

<div class="my_background_image" style="background-image: url(broken-image.jpg)">
<img class="image_error" src="broken-image.jpg" onerror="this.parentElement.style.display='none';">
</div>

Ou

onerror="this.parentElement.backgroundImage = "url('image_placeHolder.png')";

css:

.image_error {
    display: none;
}
Gino
la source