Image – Bilder laden, zeigen, austauschen

Javascript erzeugt ein Image Object mit createElement oder new Image. Das Image-Objekt ist kein Bestandteil der Programmiersprache wie Date(), Array() oder String(), sondern gehört zum Document Object Model. Das Objekt hat keine Methoden, sondern nur Eigenschaften wie src, width, height, naturalWidth ….

Javascript image

new Image

Es macht kaum einen Unterschied, ob das Bild mit createElement oder mit new Image angelegt wird. Allenfalls könnte man ins Feld räumen, dass createElement konsistenter ist.

Bilder können in Javascript also mit

const myImg = document.createElement('img');

oder mit

const myImg = new Image();

angelegt werden.

Zweck Methode Empfehlung
Bild preladen new Image() Schnell und kompakt
Bild dynamisch mit CSS/Events usw. createElement("img") Flexibler und kontrollierter
Bild mit festen Abmessungen new Image(w, h) Kurz und nützlich

Bild laden async/await

Bilder werden geladen, nachdem ein HTTP-Request für das Bild abgesendet wurde. Das passiert entweder durch ein img-Tag oder durch einen Funktionsaufruf.

Wird das Skript mit defer im Kopf des HTML-Dokuments geladen, dann ist das HTML komplett geparst, das DOM aufgebaut, das img-Tag existiert. Danach entsteht DOMContentLoaded, aber CSS-Dateien, Bilder und iframes sind noch nicht geladen. Der gleiche Ablauf entsteht, wenn Medien z.B. mit Javascript aufgrund einer Benutzeraktion geladen werden.

Als früher nur Events, aber keine Promises zur Verfügung standen, war die Feststellung, ob ein Bild geladen war, kompliziert. Darüber hinaus ist beim beim load-Event das Bild zwar bereits geladen, aber noch nicht dekodiert (in Pixel umgewandelt). Heute sorgen async/await und ein sauberes Fehler-Handling für einen einfachen Ablauf:

<button id="decode" class="btn">decode</button>

Old style, aber immer noch OK

button.addEventListener ('click', () => {
	const img = document.createElement ('img');
	img.alt = `Bild mit JavaScript laden`;
	console.log ('1️⃣ img-Tag erzeugt');
	img.addEventListener ("load", function () {
		console.log ('2️⃣ Bild geladen');
		document.querySelector('section').append(img);
	});
	console.log ('3️⃣ Bildquelle');
	img.src='image.webp';
});

async/await und decode – Performance-Feinschliff

const decodeBtn = document.querySelector("#decode");

decodeBtn.addEventListener("click", async () => {
	console.log ('1️⃣ img-Tag erzeugt');
	const img = new Image();
	img.src = "image.webp";

	try {
		await img.decode(); // 2️⃣ wartet bis Bild dekodiert ist
		// 3️⃣ img-Tag ins DOM hängen
		document.querySelector("section").append(img);
	} catch (err) {
		console.error("Fehler beim Laden:", err);
	}
});

Eigenschaften des Image Object: Image Properties

alt
Setzt das alt-Attribut oder gibt den Wert des alt-Attributs zurück
complete
Gibt zurück, ob der Browser das Bild vollständig geladen hat. complete ist kein Event!, sondern gibt true oder false zurück.
crossOrigin
Setzt die CORS-Einstellung (Cross Origin) oder gibt sie zurück
height
Setzt die Höhe des Bildes oder gibt des Wert des height-Attributs zurück
isMap
Setzt ein Bild als Teil einer serverseitigen Image Map oder gibt zurück, ob das Bild Teil einer server-seitigen Image Map ist
naturalHeight
Gibt die (physikalische) Höhe des Bildes zurück
naturalWidth
Gibt die (physikalische) Breite des Bildes zurück. Das Bild muss vollständig geladen sein, bevor die Größe des Originals mit Javascript naturalHeight und naturalWidth bestimmt werden kann (ab IE9).
src
Setzt das src-Attribut des Bildes oder gibt des Wert des src-Attributs zurück
useMap
Setzt das useMap-Attribut des Bildes oder gibt den Wert des useMap-Attributs zurück
width
Setzt die Breite des Bildes oder gibt des Wert des width-Attributs zurück
align, border, hspace, longDesc, name, vspace
veraltet und nicht mehr in HTML5 vertreten

Javascript fetch HEAD kann schon vor dem Laden des Bildes die Dateigröße auslesen, während die Abmessungen des Bildes erst nach dem Laden abgefragt werden können.

decode – Bild vollständig dekodiert

decode() ist eine Methode des HTMLImageElement und sorgt dafür, dass ein Bild vollständig dekodiert (Pixel im Speicher) ist, bevor es benutzt wird.

Die Methode ist immer dann angebracht, wenn Bilder dynamisch einfügt werden, bei Bildwechsel-Animationen, wenn ein Hero-Image mit preload vorbereitet wird, wenn Canvas drawImage verwendet wird. decode() vermeidet einen eventuellen Layout-Shift beim »Aufpoppen« des Bildes.

Methode Beschreibung
decode() Gibt ein Promise zurück, das sich auflöst, wenn das Bild dekodiert ist.
await img.decode(); Warte, bis das Bild vollständig im Speicher vorbereitet ist

Spinner zeigen, bis ein Bild geladen ist

Da bei sehr großen Bildern eine Weile ins Land gehen kann, bis der Browser das Bild vollständig geladen hat, zeigen Galerien und Slideshows einen Spinner.

Der HTML-Teil ist einfach


<div id="buffalo">
	<img id="thumbnail" src="buffalo-mini.webp" width="250" height="145" … >
</div>

buffalo-mini
Klick für die große Version

Das Skript erzeugt beim Klick auf den Thumbnail ein Element für den Overlay und ein Element für den Spinner. Die große Version des Bildes wird erst mit dem Klick erzeugt. Bis das Bild im Browser geladen ist, dreht sich der Spinner.

document.getElementById("thumbnail").addEventListener("click", async () => {
  const container = document.getElementById("container");

  // Spinner erzeugen
  const spinner = document.createElement("div");
  spinner.className = "spinner";
  container.replaceChildren(spinner);

  try {
    const img = new Image();
    img.src = "buffalo-mini-2500.webp";

    await img.decode(); // wartet bis dekodiert

    container.replaceChildren(img); // Spinner ersetzen

  } catch (err) {
    container.textContent = "Fehler beim Laden";
    console.error(err);
  }
});
  1. Spinner wird sofort gerendert
  2. Bild lädt im Hintergrund
  3. decode() wartet auf vollständige Dekodierung
  4. DOM wird erst danach aktualisiert
  5. Kein Layout-Ruckeln

Image Preload mit Javascript

Wenn ein Image Objekt erzeugt wurde und dem Objekt eine URL zugewiesen wird, lädt der Browser das Bild in den Cache, um das Bild später bei einem Klick auf einen Button oder nach längerem Scrollen ohne Verzögerung anzuzeigen.

<script>
let myImage = new Image();
myImage.src = 'einbild.jpg';
</script>

Das ist heute nicht mehr besonders sinnvoll, denn die Browser priorisieren LCP (Largest Contentful Paint – der Zeitpunkt, an dem das größte sichtbare Element der Seite im Viewport vollständig gerendert ist) selbst und erkennen das wichtigste Bild automatisch. Mit HTTP/2 und HTTP/3 ist Multiplexing besser geeignet.

An dieser Stelle hat der Browser das Bild in den Cache geladen und das Image-Objekt myImage enthält das Bild einbild.jpg.

Heute kann allerdings ein Link mit rel="preload" im Head der Seite Ressourcen (Bilder, CSS, Scripte) elegant nach dem Laden der Seite im Voraus laden, z.B. um sie erst später auf der Seite zu zeigen oder zu dekodieren (in Pixel umwandeln).

<link rel="preload" as="image" href="largemap.png" media="(max-width: 600px)">

Alternativ sorgt das HTML-Attribut loading="lazy" dafür, dass Bilder erst geladen werden, wenn der Benutzer bis in die Nähe des Bildes scrollt. So blockiert die das Rendern des Bildes das Rendern der Seite nicht. preload wird dadurch nicht automatisch überflüssig, die Kombination kann sogar optimal sein, allerdings nur bei wichtigen Bildern, bei Slidern und Lightboxen.

<img src="gallery/hero.webp" fetchpriority="high" loading="eager">

naturalWidth / naturalHeight: Größe eines Bildes

Für Slideshows und die allgegenwärtigen Lightboxen ist es oft erforderlich, die tatsächliche Größe eines Bildes herauszufinden.

Bilder werden als Thumbnail oder Vorschaubild kleiner in Webseiten gesetzt (z.B. damit sie in das Layout der Seite passen). Erst für die Darstellung in der Lightbox wird ihre »natürliche Größe« gebraucht.

image size with Javascript
<img id="theImage" src="image.png" alt="image size" width="400" height="240">

const theImage = document.getElementById("theImage");
let width = theImage.width;
let height = theImage.height;

theImage.width und theImage.height liefern nur die aktuelle Größe.

let natWidth = theImage.naturalWidth;
let natHeight = theImage.naturalHeight;

naturalWidth und naturalHeight liefern die physikalischen Abmessungen – die Größe des Bildes in Pixel – in allen gängigen Browsern.

let theImage = document.getElementById("theImage");
let natWidth;
let natHeight;
if (theImage) {
    if (typeof theImage.naturalWidth == "undefined") {
        let i = new Image();
        i.src = theImage.src;
        natWidth = i.width;
        natHeight = i.height;
	} else {
        natWidth = theImage.naturalWidth;
        natHeight = theImage.naturalHeight;
	}
    theImage.classList.toggle('moveup');
    document.getElementById('imgNaturalSize').innerHTML = "Breite " + natWidth + "px Höhe " + natHeight + 'px';
} else {
    theImage.classList.toggle('moveup');
    document.getElementById('imgNaturalSize').innerHTML = "Bild noch nicht geladen";
}

Eingebaute DOM-Objekte – kleine Helfer

Es gibt zahlreiche »kleine« DOM-Objekte, mit denen Elemente des DOM effzient und ausdrucksstark angesprochen werden. new Option erzeugt ein neues option-Element für ein HTML select und gehört neben new Image zu den eingebauten Objekten des DOM, die als kleine Helfer wirken.

const opt = new Option("Lebkuchen", "sid402", true, false);
document.querySelector("select").add(opt);

Das ist schneller als document.createElement("option").

Das komfortable Zusammenstellen eines POST-Requests mit new FormData:

const fd = new FormData();
fd.append("artikel", "Wanderstiefel");
Suchen auf mediaevent.de