J'essaie d'optimiser la taille de mon site lorsqu'il est envoyé au client. Je suis en baisse à 1,9 Mo et 29 Ko lors de la mise en cache. Le problème est que le premier chargement contient une image qui est très non optimisée pour les appareils mobiles; il a une résolution de 1080p.
Je cherche donc une méthode qui me permette de charger une version basse résolution (min.bg.jpg
) et une fois le site chargé, utilisez une version haute résolution - ou même une résolution proche de celle de l'appareil. utilisé (NNNxNNN.bg.jpg
ou simplement bg.jpg
).
L'arrière-plan est défini à l'aide de CSS, comme tout le monde s'y attendait. Son appliqué au corps et la déclaration entière ressemble à ceci:
body {
background: url("/cdn/theme/images/bg.jpg");
color: white;
height: 100%;
width: 100%;
background-repeat: no-repeat;
background-position: 50% 50%;
background-attachment: fixed;
}
Maintenant, je veux changer cela pour utiliser min.bg.jpg
à la place pour le premier chargement, et ensuite quelque chose comme ceci:
jQuery(function(){
jQuery("body").[...]
});
De quelle manière puis-je télécharger de manière asynchrone le nouvel arrière-plan, puis l'insérer en tant que nouvelle image d'arrière-plan CSS?
Pour montrer quelques différences, voici un exemple de la version principale et de la version mini que j'utilise pour les tests:
[email protected] ~/Work/BIRD3/cdn/theme/images $ file *.jpg
bg.jpg: JPEG image data, EXIF standard
min.bg.jpg: JPEG image data, JFIF standard 1.01
[email protected] ~/Work/BIRD3/cdn/theme/images $ du -h *.jpg
1,0M bg.jpg
620K min.bg.jpg
Voici la méthode que j'utilise ...
CSS:
#div_whatever {
position: whatever;
background-repeat: no-repeat;
background-position: whatever whatever;
background-image: url(dir/image.jpg);
/* image.jpg is a low-resolution at 30% quality. */
}
#img_highQuality {
display: none;
}
HTML:
<img id="img_highQuality" src="dir/image.png">
<!-- img.png is a full-resolution image. -->
<div id="div_whatever"></div>
JQUERY:
$("#img_highQuality").off().on("load", function() {
$("#div_whatever").css({
"background-image" : "url(dir/image.png)"
});
});
// Side note: I usually define CSS arrays because
// I inevitably want to go back and add another
// property at some point.
Ce qui se produit:
PURE JS VERSION
Cet exemple serait efficace pour changer un à plusieurs éléments.
CSS:
.hidden {
display: none;
}
#div_whatever {
position: whatever;
background-repeat: no-repeat;
background-position: whatever whatever;
background-image: url(dir/image.jpg);
/* image.jpg is a low-resolution at 30% quality. */
}
HTML:
<div id="div_whatever"></div>
<img id="img_whatever" class="hidden" src="dir/image.png" onload="upgradeImage(this);">
JAVASCRIPT:
function upgradeImage(object) {
var id = object.id;
var target = "div_" + id.substring(4);
document.getElementById(target).style.backgroundImage = "url(" + object.src + ")";
}
MISE À JOUR/AMÉLIORATION (31/01/2017)
Cette amélioration est inspirée par l'excellent point de gdbj selon lequel ma solution a pour résultat que le chemin de l'image est spécifié à trois emplacements. Bien que je n'aie pas utilisé la technique addClass () de gdbj , le code jQuery suivant est modifié pour extraire le chemin de l'image (plutôt qu'il est câblé dans le code jQuery). Plus important encore, cette version permet plusieurs substitutions d’images de basse à haute résolution.
CSS
.img_highres {
display: none;
}
#div_whatever1 {
width: 100px;
height: 100px;
background-repeat: no-repeat;
background-position: center center;
background-image: url(PATH_TO_LOW_RES_PHOTO_1);
}
#div_whatever2 {
width: 200px;
height: 200px;
background-repeat: no-repeat;
background-position: center center;
background-image: url(PATH_TO_LOW_RES_PHOTO_2);
}
HTML
<div id="div_whatever1"></div>
<img id="img_whatever1" class="img_highres" src="PATH_TO_HIGH_RES_PHOTO_1">
<div id="div_whatever2"></div>
<img id="img_whatever2" class="img_highres" src="PATH_TO_HIGH_RES_PHOTO_2">
JQUERY
$(function() {
$(".img_highres").off().on("load", function() {
var id = $(this).attr("id");
var highres = $(this).attr("src").toString();
var target = "#div_" + id.substring(4);
$(target).css("background-image", "url(" + highres + ")");
});
});
Qu'est-ce qui se passe:
Essayons une base:
<img border="0"
style="background:url(http://i.stack.imgur.com/zWfJ5.jpg) no-repeat;
width:1920px;
height:1200px"
src="http://i.stack.imgur.com/XOYra.jpg" width="1920" height="1200" />
zWfJ5.jpg
est la version basse résolution, et XOYra.jpg
est la version haute résolution.
S'il existe un moyen d'organiser le chargement de sorte que l'image d'arrière-plan s'affiche en premier, cela pourrait être le plus simple que je puisse imaginer.
et la haute résolution est de 1,16M
résultat :
jsFiddled here (Cela nécessite une image plus grande pour la comparaison de chargement.)
Un peu tard, mais vous pouvez utiliser cette solution extrêmement simple: Vous pouvez mettre les deux images dans le fond css:
background-image: url("high-res.jpg"),url("low-res.jpg");
Le navigateur affichera le poing de l'image basse résolution, puis affichera la haute résolution sur la basse résolution une fois celle-ci chargée.
Normalement, j'optimiserais l'image à l'aide de Grunt ou d'un outil en ligne tel que Tiny PNG pour réduire la taille du fichier.
Ensuite, vous pouvez choisir de différer le chargement des images. J'ai trouvé l'article suivant utile pour reporter des images - https://www.feedthebot.com/pagespeed/defer-images.html
L'article décrit l'utilisation d'une image base64 pour le chargement initial, puis diffère le chargement de l'image de haute qualité. L'image balisée mentionnée dans l'article est la suivante ...
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="your-image-here">
Le JavaScript mentionné dans l'article est le suivant ...
<script type="text/javascript" async>
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
}
}
}
window.onload = init;
</script>
J'espère que ça aide.
Sur Ubuntu/Chrome 71, la réponse de Milche ne fonctionne pas systématiquement pour moi et l'image de résolution supérieure (via img src
) se charge et se résout avant que l'image de résolution inférieure (via css background
) ne commence même à télécharger.
Ma solution consiste à commencer par l'image de la résolution inférieure en tant que src
et à utiliser la classe Image
class pour créer une instance <img>
non attachée avec l'image en résolution élevée. Une fois qu'il est chargé, mettez à jour la source <img>
existante avec la source d'image haute résolution.
HTML:
<img id='my-image' src='low-res.png' alt='Title' width='1920px' height='1200px'>
JavaScript:
window.addEventListener('load', function() {
loadHighResImage(document.getElementById('my-image'), 'high-res.png')
})
function loadHighResImage(elem, highResUrl) {
let image = new Image()
image.addEventListener('load', () => elem.src = highResUrl)
image.src = highResUrl
}
Fiddle: https://jsfiddle.net/25aqmd67/
Cette approche fonctionne pour les images de résolution inférieure qui sont simplement réduites.
Toutes les réponses ci-dessus fonctionnent généralement avec un petit ajustement, mais voici la façon dont je pense être simple et rapide.
Remarque: - Décommentez le code chargez l'image haute résolution avant de l'utiliser, une fonction de veille sert uniquement à simuler un réseau lent . - En fait, cette méthode ne charge pas 2 ressources simultanément (haut et bas), mais elle est acceptable car le chargement de ressources faibles ne prend pas beaucoup de temps . - Copiez tout le code et lancez-vous pour une vérification rapide.
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<style type="text/css">
</style>
</head>
<body>
<!-- Load low res image first -->
<img style="width: 400px; height: auto;" alt="" src="https://s3-ap-southeast-1.amazonaws.com/wheredat/banner-low-quality/banner_20180725_123048.jpg" onload="upgrade(this)">
</body>
<script type="text/javascript">
function upgrade(image){
// After load low res image, remove onload listener.
// Remove onload listener.
$(image).prop("onload", null);
// Load high resolution image.
// $(image).attr('src', 'https://s3-ap-southeast-1.amazonaws.com/wheredat/banner/banner_20180725_123048.jpeg');
// Simulate slow network, after 1.5s, the high res image loads.
sleep(1500).then(() => {
// Do something after the sleep!
// Load a high resolution image.
$(image).attr('src', 'https://s3-ap-southeast-1.amazonaws.com/wheredat/banner/banner_20180725_123048.jpeg');
});
}
// Sleep time expects milliseconds
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
</script>
</html>
Avez-vous essayé d'utiliser des sprites CSS pour vous aider à obtenir ce que vous voulez? http://css-tricks.com/css-sprites/