Préchargement des images CSS

118

J'ai un formulaire de contact caché qui est déployé en cliquant sur un bouton. Ses champs sont définis comme des images d'arrière-plan CSS, et ils apparaissent toujours un peu plus tard que le div qui a été basculé.

J'utilisais cet extrait dans la <head>section, mais sans chance (après avoir vidé le cache):

<script>
$(document).ready(function() {
        pic = new Image();
        pic2 = new Image();
        pic3 = new Image();
        pic.src="<?php bloginfo('template_directory'); ?>/images/inputs/input1.png";
        pic2.src="<?php bloginfo('template_directory'); ?>/images/inputs/input2.png";
        pic3.src="<?php bloginfo('template_directory'); ?>/images/inputs/input3.png";
});
</script>

J'utilise jQuery comme bibliothèque, et ce serait cool si je pouvais l'utiliser également pour organiser ce problème.

Merci pour vos réflexions.

Cacahuètes
la source
Veuillez montrer votre code. Comment basculer ce formulaire?
n1313
1
n1313, j'utilise le moyen le plus simple possible: $ ('# toggle'). click (function () {$ ('# contact'). slideToggle ();});
Peanuts

Réponses:

257

Préchargement d'images en utilisant uniquement CSS

Dans le code ci-dessous, je choisis au hasard l' bodyélément, car c'est l'un des seuls éléments garantis d'exister sur la page.

Pour que le "truc" fonctionne, nous utiliserons la contentpropriété qui permet confortablement de définir plusieurs URL à charger, mais comme indiqué, le ::afterpseudo élément est caché afin que les images ne soient pas rendues:

body::after{
   position:absolute; width:0; height:0; overflow:hidden; z-index:-1; // hide images
   content:url(img1.png) url(img2.png) url(img3.gif) url(img4.jpg);   // load images
}

Démo


il vaut mieux utiliser une image sprite pour réduire les requêtes http ... (s'il y a beaucoup d'images de taille relativement petite) et s'assurer que les images sont hébergées là où HTTP2 est utilisé.

vsync
la source
27
C'est génial!
Hengjie
4
Meilleure technique à ce jour pour sa simplicité et son approche CSS pure! Le seul inconvénient est que ces images sont chargées en même temps que le contenu immédiatement visible, et ne sont pas retardées jusqu'à ce que le contenu principal ait été chargé, ce qui nécessiterait du Javascript. Mais à moins que vous ne préchargiez des dizaines d'images, cela ne devrait pas être un facteur décisif.
Benjamin
2
c'est fantastique pour précharger les ressources de survol pour les boutons CSS et autres - de cette façon, vous n'obtenez aucun scintillement lorsque vous passez sur votre bouton pendant le chargement des ressources
Robert Petz
16
Bonne solution. bodyCependant, je recommanderais de ne pas appliquer cela à , car ces images seront chargées sur chaque page qui fait référence à la feuille de style. Au lieu de cela, vous devriez utiliser .contact_form:after {...}ou une autre classe moins globale. Sauf, bien sûr, votre formulaire de contact est sur chaque page;)
CloudMagick
3
@vsync, cela a du sens, en particulier pour les gifs et les petits réutilisables. La situation que j'ai rencontrée récemment concernait de grandes images bg pour un carrousel riche en contenu, et je ne voulais certainement pas que ces gros fichiers
soient
30

Je peux confirmer que mon code d'origine semble fonctionner. Je m'en tenais négligemment à une image avec un mauvais chemin.

Voici un test: http://paragraphe.org/slidetoggletest/test.html

<script>
    var pic = new Image();
    var pic2 = new Image();
    var pic3 = new Image();
    pic.src="images/inputs/input1.png";
    pic2.src="images/inputs/input2.png";
    pic3.src="images/inputs/input3.png";
</script>
Cacahuètes
la source
Après quelques tests avec CSS-ONLY et cette solution, dans mon cas en particulier, c'est la meilleure.
zequinha-bsb
Merci, c'est le plus
simple
4
L'URL de la réponse n'est plus valide.
Brandon Buck
Bonjour, j'ai re-uploadé le contenu sur cette URL ( paragraphe.org/slidetoggletest/test.html ), désolé de l'avoir manqué. Cheers,
Peanuts
25

Préchargement d'images à l'aide de la balise HTML <link>

Je crois que la plupart des visiteurs de cette question recherchent la réponse "Comment puis-je précharger une image avant le début du rendu de la page?" et la meilleure solution à ce problème consiste à utiliser une <link>balise car la <link>balise est capable de bloquer le rendu ultérieur de la page. Voir préventif

Ces deux options de valeur de l' attribut rel( relation entre le document actuel et le document lié ) sont les plus pertinentes pour le problème:

  • prefetch : charge la ressource donnée lors du rendu de la page
  • préchargement : charge la ressource donnée avant le début du rendu de la page

Donc, si vous souhaitez charger une ressource ( dans ce cas, c'est une image ) avant le début du processus de rendu de la <body>balise, utilisez:

<link rel="preload" as="image" href="IMAGE_URL">

et si vous souhaitez charger une ressource pendant le <body>rendu mais que vous prévoyez de l'utiliser ultérieurement de manière dynamique et que vous ne voulez pas déranger l'utilisateur avec le temps de chargement, utilisez:

<link rel="prefetch" href="RESOURCE_URL">
mertyildiran
la source
Il convient de noter que le moteur de navigateur Mozilla ne se chargera que prefetchlorsque le navigateur est inactif, ce qui est déterminé par l' nsIWebProgressListenerAPI. Voir ceci pour plus d'informations.
Matthew Beckman
1
Je ne pense pas que cela bloque réellement le rendu: w3c.github.io/preload "Par exemple, l'application peut utiliser le mot-clé preload pour lancer une extraction précoce, haute priorité et sans blocage du rendu d'une ressource CSS qui peut ensuite être appliqué par l'application au moment opportun "
Michael Crenshaw
1
@MichaelCrenshaw est correct, <link rel="preload">ne bloque pas le rendu, je crois que l'auteur a mal compris la définition. Depuis MDN Preloading content avec rel = "preload" , "... que vous voulez commencer à charger tôt dans le cycle de vie de la page, avant que la principale machine de rendu des navigateurs ne démarre." L'idée est que les ressources sont récupérées dès que possible, ce qui augmente la probabilité que la ressource soit disponible en cas de besoin, par exemple lorsqu'un <img>élément est rendu.
MDMower
14

http://css-tricks.com/snippets/css/css-only-image-preloading/

Technique n ° 1

Chargez l'image sur l'état normal de l'élément, décalez-la uniquement avec la position d'arrière-plan. Déplacez ensuite la position de l'arrière-plan pour l'afficher en survol.

#grass { background: url(images/grass.png) no-repeat -9999px -9999px; }
#grass:hover { background-position: bottom left; }

Technique n ° 2

Si l'élément en question a déjà une image d'arrière-plan appliquée et que vous devez changer cette image, ce qui précède ne fonctionnera pas. En général, vous optez pour un sprite ici (une image d'arrière-plan combinée) et déplacez simplement la position d'arrière-plan. Mais si ce n'est pas possible, essayez ceci. Appliquez l'image d'arrière-plan à un autre élément de page qui est déjà utilisé, mais qui n'a pas d'image d'arrière-plan.

#random-unsuspecting-element { background: url(images/grass.png) no-repeat -9999px -9999px; }
#grass:hover { background: url(images/grass.png) no-repeat; }
Fatih Hayrioğlu
la source
4
Fournissez toujours le contenu des liens externes. Sinon, votre réponse est sans valeur si le lien se rompt!
sra
@Fatih +1 pour un très bon lien. Version plus récente de l'article lié avec 3 façons différentes est ici perishablepress.com/3-ways-preload-images-css-javascript-ajax
xmojmr
@xmojmr Il n'y a pas de solution CSS uniquement dans votre lien.
Max
10

essayez avec ceci:

var c=new Image("Path to the background image");
c.onload=function(){
   //render the form
}

Avec ce code, vous préchargez l'image d'arrière-plan et effectuez le rendu du formulaire lorsqu'il est chargé

mck89
la source
mck89, merci cela semble plutôt bon. Mais, dois-je utiliser ce code à l'intérieur de la «tête» ou en ligne? Je veux dire, dois-je le remplir avec du html?
Peanuts
Vous devez l'utiliser dans la tête. Je pense que vous pouvez l'utiliser dans le $ (document) .ready
mck89
6

Pour le préchargement des images d'arrière-plan définies avec CSS, la réponse la plus efficace que j'ai trouvée était une version modifiée d'un code que j'ai trouvé qui ne fonctionnait pas:

$(':hidden').each(function() {
  var backgroundImage = $(this).css("background-image");
  if (backgroundImage != 'none') {
    tempImage = new Image();
    tempImage.src = backgroundImage;
  }
});

L'avantage énorme de ceci est que vous n'avez pas besoin de le mettre à jour lorsque vous apportez de nouvelles images d'arrière-plan à l'avenir, il trouvera les nouvelles et les préchargera!

Deminetix
la source
Dois-je bien comprendre que vous ajoutez un élément caché pour chaque image? Ce n'est pas qu'il est capable de scanner votre fichier CSS pour les images, n'est-ce pas? :)
bvdb
5

Si vous réutilisez ces images bg n'importe où ailleurs sur votre site pour les entrées de formulaire, vous souhaiterez probablement utiliser un sprite d'image. De cette façon, vous pouvez gérer vos images de manière centralisée (au lieu d'avoir pic1, pic2, pic3, etc ...).

Les sprites sont généralement plus rapides pour le client, car ils ne demandent qu'un seul fichier (quoique légèrement plus gros) au serveur au lieu de plusieurs fichiers. Voir l'article SO pour plus d'avantages:

Sprites d'image CSS

Là encore, cela peut ne pas être utile du tout si vous ne les utilisez que pour un formulaire et que vous ne voulez vraiment les charger que si l'utilisateur demande le formulaire de contact ... cela peut cependant avoir du sens.

http://www.alistapart.com/articles/sprites

ajhit406
la source
Oui, les sprites CSS sont la voie à suivre. Assurez-vous simplement qu'une des images de ce sprite apparaît avant le lancement du formulaire masqué (comme lors du chargement de la page).
Steve
1

que diriez-vous de charger cette image de fond quelque part cachée. De cette façon, il sera chargé lorsque la page est ouverte et ne prendra pas de temps une fois que le formulaire est créé en utilisant ajax:

body {
background: #ffffff url('img_tree.png') no-repeat -100px -100px;
}
Santi
la source
1

Vous pouvez utiliser ce plugin jQuery waitForImage ou vous pouvez mettre vos images dans un div caché ou (largeur: 0 et hauteur: 0) et utiliser l'événement onload sur les images.

Si vous n'avez que 2-3 images, vous pouvez lier des événements et les déclencher dans une chaîne afin qu'après chaque image, vous puissiez faire du code.

user1236048
la source
1

Le seul moyen est d'encoder l'image en Base64 et de la placer dans le code HTML afin qu'il n'ait pas besoin de contacter le serveur pour télécharger l'image.

Cela encodera une image à partir de l'URL afin que vous puissiez copier le code du fichier image et l'insérer dans votre page comme ceci ...

body {
  background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...);
}
maudit
la source
2
si vous souhaitez à nouveau utiliser la même image dans votre CSS ... elle ne sera pas mise en cache et vous devrez la charger à nouveau.
vsync
1

Lorsqu'il n'y a aucun moyen de modifier le code CSS et de précharger des images avec des règles CSS :beforeou des :afterpseudo éléments, une autre approche avec du code JavaScript traversant les règles CSS des feuilles de style chargées peut être utilisée. Pour que cela fonctionne, les scripts doivent être inclus après les feuilles de style en HTML, par exemple, avant de fermer la bodybalise ou juste après les feuilles de style.

getUrls() {
    const urlRegExp = /url\(('|")?([^'"()]+)('|")\)?/;

    let urls = [];
    for (let i = 0; i < document.styleSheets.length; i++) {
        let cssRules = document.styleSheets[i].cssRules;
        for (let j = 0; j < cssRules.length; j++) {
            let cssRule = cssRules[j];
            if (!cssRule.selectorText) {
                continue;
            }

            for (let k = 0; k < cssRule.style.length; k++) {
                let property = cssRule.style[k],
                    urlMatch = cssRule.style[property].match(urlRegExp);
                if (urlMatch !== null) {
                    urls.push(urlMatch[2]);
                }
            }
        }
    }
    return urls;
}

preloadImages() {
    return new Promise(resolve => {
        let urls = getUrls(),
            loadedCount = 0;

        const onImageLoad = () => {
            loadedCount++;
            if (urls.length === loadedCount) {
                resolve();
            }
        };

        for (var i = 0; i < urls.length; i++) {
            let image = new Image();
            image.src = urls[i];
            image.onload = onImageLoad;
        }
    });
}

document.addEventListener('DOMContentLoaded', () => {
    preloadImages().then(() => {
        // CSS images are loaded here
    });
});
Ezze
la source
0

Si les éléments de la page et leurs images d'arrière-plan sont déjà dans le DOM (c'est-à-dire que vous ne les créez pas / ne les modifiez pas dynamiquement), alors leurs images d'arrière-plan seront déjà chargées. À ce stade, vous voudrez peut-être examiner les méthodes de compression :)


la source
mmmm ... bon point cpharmston, et cela explique pourquoi le problème persiste même avec les images en cache. Donc, cela signifie qu'il n'y a pas de solution de contournement?
Peanuts
Créez des images plus petites! Les JPEG sont facilement compressés, il existe des outils en ligne de commande pour réduire la taille des PNG ( pmt.sourceforge.net/pngcrush ), et vous pouvez réduire le nombre de couleurs dans l'image pour réduire la taille des GIF. Bien sûr, vous pouvez également vous