webentwicklung-frage-antwort-db.com.de

Laden Sie zuerst ein Hintergrundbild mit niedriger Auflösung und dann ein Hintergrundbild mit hoher Auflösung

Ich versuche, die Größe meiner Site zu optimieren, wenn sie an den Client ausgegeben wird. Beim Zwischenspeichern bin ich auf 1,9 MB und 29 KB eingestellt. Das Problem ist, dass der erste Ladevorgang ein Image enthält, das für mobile Geräte sehr unoptimiert ist. Es hat eine Auflösung von 1080p.

Ich suche also nach einer Methode, mit der ich zuerst eine niedrigauflösende Version (min.bg.jpg) laden kann, und nachdem die Site geladen wurde, eine hochauflösende Version verwenden - oder sogar eine, deren Auflösung nahe am verwendeten Gerät liegt (NNNxNNN.bg.jpg oder einfach bg.jpg).

Der Hintergrund wird mithilfe von CSS so eingestellt, wie jeder es erwarten würde. Seine Anwendung auf den Körper und die gesamte Anweisung sieht folgendermaßen aus:

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;
}

Jetzt möchte ich das ändern, um stattdessen min.bg.jpg für das erste Laden zu verwenden, und dann etwas wie das Folgende:

jQuery(function(){
    jQuery("body").[...]
});

Wie kann ich den neuen Hintergrund asynchron herunterladen und als neues CSS-Hintergrundbild einfügen?

Um einige Unterschiede aufzuzeigen, hier ein Beispiel der Haupt- und Miniversion, die ich zum Testen verwende:

[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
19
Ingwie Phoenix

Hier ist die Methode, die ich benutze ...

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.

Was geschieht:

  1. Eine niedrig aufgelöste Version des Hintergrunds wird schnell geladen.
  2. Inzwischen wird die Version mit höherer Auflösung als verstecktes Bild geladen.
  3. Wenn das hochaufgelöste Bild geladen wird, tauscht jQuery das niedrig aufgelöste Bild des div mit der hochauflösenden Version.

PURE JS VERSION

Dieses Beispiel wäre effizient, um ein Element in viele Elemente zu ändern.

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 + ")";
}

UPDATE/VERBESSERUNG (31.01.2017)

Diese Verbesserung basiert auf dem hervorragenden Punkt von gdbj , dass meine Lösung dazu führt, dass der Bildpfad an drei Stellen angegeben wird. Obwohl ich die addClass () - Methode von gdbj nicht verwendet habe, wird der folgende jQuery-Code geändert, um den Image-Pfad zu extrahieren (anstatt ihn in den jQuery-Code zu verdrahten). Noch wichtiger ist, dass diese Version mehrere Bildersetzungen mit niedriger Auflösung bis zu hoher Auflösung ermöglicht. 

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 + ")");
      });
   });

Was passiert:

  1. Bilder mit niedriger Auflösung werden für jedes der divs basierend auf ihren CSS-Hintergrundbildeinstellungen geladen. (Beachten Sie, dass das CSS auch das div auf die beabsichtigten Dimensionen Setzt.) 
  2. Inzwischen werden die Fotos mit höherer Auflösung Als versteckte Bilder geladen (alle haben den Klassennamen img_highres). 
  3. Eine jQuery-Funktion wird jedes Mal ausgelöst, wenn ein img_highres-Foto Vollständig geladen wird. 
  4. Die jQuery-Funktion liest den Image-Quellpfad, und Ändert das Hintergrundbild des entsprechenden div. Im obigen -Beispiel lautet die Namenskonvention "div_ [name]" für die sichtbaren divs Und "img_ [same name]" für die hochaufgelösten Bilder, die im Hintergrund geladen werden.
14
Alan M.

Versuchen wir es mit einem einfachen:

<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 ist die niedrigauflösende Version und XOYra.jpg ist die hochauflösende Version.

Wenn es eine Möglichkeit gibt, das Laden so anzuordnen, dass das Hintergrundbild zuerst angezeigt wird, könnte dies die einfachste sein, die ich mir vorstellen kann.

wo niedrige Auflösung 44k:  low resolution 44k:

und hohe Auflösung ist 1.16M  high resolution is 1.16M

ergebnis:

jsFiddled here (dies erfordert ein größeres Bild für den Ladevergleich.)

23
Milche Patern

Etwas spät, aber Sie können diese extrem einfache Lösung verwenden: Sie können die beiden Bilder in den CSS-Hintergrund einfügen:

  background-image: url("high-res.jpg"),url("low-res.jpg");

Der Browser zeigt die Bildfase mit niedriger Auflösung an und zeigt die hohe Auflösung nach dem Laden mit niedriger Auflösung an.

8
user7956100

Normalerweise würde ich das Bild mit Grunt oder einem Online-Tool wie Tiny PNG optimieren, um die Dateigröße zu reduzieren. 

Dann könnten Sie das Laden der Bilder verzögern. Ich fand den folgenden Artikel hilfreich, wenn Sie Bilder ablehnen wollten - https://www.feedthebot.com/pagespeed/defer-images.html

In diesem Artikel wird die Verwendung eines base64-Bildes für das anfängliche Laden beschrieben und anschließend das Laden des qualitativ hochwertigen Bildes verzögert. Die im Artikel erwähnte Bildmarkierung sieht wie folgt aus:.

<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="your-image-here">

Das in diesem Artikel erwähnte JavaScript lautet wie folgt ...

<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>

Ich hoffe das hilft.

1
steffcarrington

Unter Ubuntu/Chrome 71 funktioniert die Antwort von Milche für mich nicht konsistent und das Bild mit höherer Auflösung (über img src) wird häufig geladen und aufgelöst, bevor das Bild mit niedrigerer Auflösung (über css background) sogar mit dem Herunterladen beginnt.

Meine Lösung ist, mit dem Image mit niedrigerer Auflösung als src zu beginnen und die Klasse Image zu verwenden, um eine nicht gebundene <img>-Instanz mit dem hochauflösenden Image zu erstellen. Sobald es geladen ist, aktualisieren Sie die vorhandene <img>-Quelle mit der Bildquelle mit hoher Auflösung.

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
}

Geige: https://jsfiddle.net/25aqmd67/

Dieser Ansatz funktioniert für Bilder mit niedrigerer Auflösung, die einfach auch verkleinert werden.

0
Vulcan

Alle Antworten oben funktionieren meistens mit einer kleinen Anpassung, aber ich denke, es ist kurz und einfach zu beginnen. 

Hinweis: - Wenn Sie das hochaufgelöste Bild für die Verwendung des Kommentars kommentieren, ist eine Schlaffunktion nur für die Simulation eines langsamen Netzwerks vorgesehen. - Tatsächlich lädt diese Methode nicht gleichzeitig zwei Ressourcen (niedrig und hoch), aber es ist akzeptabel, da die Ressource mit geringen Ressourcen nicht lange braucht . - Kopieren Sie einfach den gesamten Code und führen Sie ihn für eine schnelle Überprüfung aus.

<!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>

0
Nguyen Tan Dat

Haben Sie versucht, mit CSS-Sprites das zu bekommen, was Sie möchten? http://css-tricks.com/css-sprites/

0