Komprimierung und Codierung automatisieren

Profitieren Sie von einem nahtlosen Generieren leistungsstarker Bildquellen in Ihrem Entwicklungsprozess.

Alle Syntaxen in diesem Kurs – von der Codierung von Bilddaten bis zum Informations-Markup für responsive Bilder – sind Methoden, über die Maschinen mit Computern kommunizieren können. Sie haben eine Reihe von Möglichkeiten entdeckt, wie ein Clientbrowser seine Anforderungen an einen Server kommunizieren kann und wie ein Server eine Art antworten kann. Das responsive Bild-Markup (insbesondere srcset und sizes) beschreibt in relativ wenigen Zeichen eine schockierende Menge an Informationen. Die Kürze liegt im Prinzip von Grund auf: Wenn diese Syntax weniger kurzlebig und für Entwickler leichter zu parsen ist, könnte sie für einen Browser schwieriger zu parsen sein. Je komplexer ein String, desto höher das Risiko von Parserfehlern oder unbeabsichtigten Unterschieden im Verhalten von einem Browser zum anderen.

Ein automatisches Bildcodierungsfenster.

Die gleiche Eigenschaft, die diese Themen so einschüchternd wirken lässt, kann Ihnen aber auch Lösungen liefern: Eine Syntax, die von Maschinen leicht gelesen werden kann, ist eine Syntax, die von ihnen leichter geschrieben werden kann. Als Nutzer des Webs sind Sie mit hoher Wahrscheinlichkeit auf viele Beispiele für die automatische Bildcodierung und -komprimierung gestoßen: Alle Bilder, die über soziale Medien, Content-Management-Systeme (CMS) und sogar E-Mail-Clients in das Web hochgeladen werden, durchlaufen fast immer ein System, das ihre Größe ändert, neu codiert und komprimiert.

Responsives Bild-Markup eignet sich ebenfalls gut für die Automatisierung – sei es über Plug-ins, externe Bibliotheken, eigenständige Build-Prozesstools oder den verantwortungsvollen Einsatz von clientseitigem Scripting.

Dies sind die beiden Hauptanliegen bei der Automatisierung der Bildleistung: die Verwaltung der Bilderstellung – ihre Codierung, Komprimierung und die alternativen Quellen, die Sie zum Ausfüllen eines srcset-Attributs verwenden – und das Generieren unseres für Nutzer sichtbaren Markups. In diesem Modul lernen Sie einige gängige Ansätze zur Verwaltung von Bildern im Rahmen eines modernen Workflows kennen, sei es als automatisierte Phase im Entwicklungsprozess, über das Framework oder Content-Management-System für Ihre Website oder fast vollständig abstrahiert durch ein spezielles Content Delivery Network.

Komprimierung und Codierung automatisieren

Es ist unwahrscheinlich, dass Sie sich die Zeit nehmen können, die ideale Codierung und Komprimierung für jedes einzelne Bild, das für ein Projekt bestimmt ist, manuell zu bestimmen – oder dies auch möchten. Es ist wichtig, die Bildübertragungsgrößen so klein wie möglich zu halten, die Feinabstimmung der Komprimierungseinstellungen und das Neuspeichern alternativer Quellen für jedes Bildasset, das für eine Produktionswebsite bestimmt ist, würde zu einem enormen Engpass bei Ihrer täglichen Arbeit führen.

Wie Sie bereits aus den verschiedenen Bildformaten und Komprimierungstypen erfahren haben, hängt die effizienteste Codierung für ein Bild immer vom Inhalt des Bildes ab. Wie Sie unter Responsive Bilder gelernt haben, werden die alternativen Größen für Ihre Bildquellen durch die Position dieser Bilder im Seitenlayout bestimmt. In einem modernen Workflow gehen Sie diese Entscheidungen ganzheitlich und nicht einzeln an und legen einen Satz sinnvoller Standardeinstellungen für Bilder fest, die am besten zu den Kontexten passen, in denen sie verwendet werden sollen.

Bei der Auswahl der Codierungen für ein Verzeichnis mit Fotobildern ist AVIF der klare Gewinner in Bezug auf Qualität und Übertragungsgröße, wird aber nur eingeschränkt unterstützt. WebP bietet ein optimiertes, modernes Fallback und JPEG ist die zuverlässigste Standardeinstellung. Die alternativen Größen, die wir für Bilder erzeugen, die eine Seitenleiste in einem Seitenlayout einnehmen sollen, unterscheiden sich stark von Bildern, die an unseren höchsten Haltepunkten den gesamten Darstellungsbereich des Browsers ausfüllen. Komprimierungseinstellungen erfordern das Unkenntlichmachen und Komprimieren von Artefakten in mehreren resultierenden Dateien. So bleibt weniger Platz, um jedes mögliche Byte aus jedem Bild auszuschöpfen, um einen flexibleren und zuverlässigeren Workflow zu erhalten. Zusammenfassend lässt sich sagen, dass Sie den gleichen Entscheidungsprozess anwenden werden, den Sie aus diesem Kurs kennen.

Was die Verarbeitung selbst betrifft, gibt es eine große Anzahl von Open-Source-Bildverarbeitungsbibliotheken, die Methoden zum Konvertieren, Ändern und Bearbeiten von Bildern in Batches bereitstellen und dabei in Sachen Geschwindigkeit, Effizienz und Zuverlässigkeit konkurrieren. Mit diesen Verarbeitungsbibliotheken können Sie Codierungs- und Komprimierungseinstellungen auf ganze Bildverzeichnisse gleichzeitig anwenden, ohne Bildbearbeitungssoftware öffnen zu müssen. Dabei müssen Ihre ursprünglichen Bildquellen erhalten bleiben, falls diese Einstellungen spontan angepasst werden müssen. Sie sind für eine Reihe von Kontexten vorgesehen, von der lokalen Entwicklungsumgebung bis hin zum Webserver selbst. So kann das auf Komprimierung ausgerichtete ImageMin für Node.js über ein Array von Plug-ins für bestimmte Anwendungen erweitert werden. Das plattformübergreifende ImageMagick und das auf Node.js basierende Sharp bieten hingegen sofort eine beeindruckende Anzahl von Funktionen.

Mit diesen Bildverarbeitungsbibliotheken können Entwickler Tools zur nahtlosen Optimierung von Bildern im Rahmen Ihrer Standardentwicklungsprozesse erstellen. So sorgen Sie dafür, dass Ihr Projekt immer auf produktionsreife Image-Quellen mit so wenig Aufwand wie möglich verweist.

Lokale Entwicklungstools und Workflows

Task-Runner und Bundler wie Grunt, Gulp oder Webpack können verwendet werden, um Bild-Assets neben anderen gängigen leistungsbezogenen Aufgaben wie der Reduzierung von CSS und JavaScript zu optimieren. Nehmen wir zur Veranschaulichung einen relativ einfachen Anwendungsfall: Ein Verzeichnis in Ihrem Projekt enthält ein Dutzend Fotografien, die auf einer öffentlich zugänglichen Website verwendet werden sollen.

Zunächst müssen Sie für eine einheitliche und effiziente Codierung dieser Bilder sorgen. Wie Sie in den vorherigen Modulen gelernt haben, ist WebP sowohl im Hinblick auf Qualität als auch auf Dateigröße ein effizienter Standard für fotografische Bilder. WebP wird gut unterstützt, aber nicht universal. Daher sollten Sie auch ein Fallback in Form einer progressiven JPEG-Datei einbinden. Damit Sie das srcset-Attribut für eine effiziente Bereitstellung dieser Assets nutzen können, müssen Sie dann mehrere alternative Größen für jede Codierung erstellen.

Dies wäre zwar eine sich wiederholende und zeitaufwändige lästige Arbeit in Verbindung mit einer Bildbearbeitungssoftware, doch Aufgaben-Runner wie Gulp sind darauf ausgelegt, genau diese Art von Wiederholungen zu automatisieren. Das gulp-responsive-Plug-in, das Sharp verwendet, ist eine Option von vielen, die einem ähnlichen Muster folgen: Alle Dateien werden in einem Quellverzeichnis erfasst, neu codiert und basierend auf derselben standardisierten Kurzschreibweise für „Qualität“ komprimiert, die Sie unter Bildformate und Komprimierung kennengelernt haben. Die resultierenden Dateien werden dann an einen von Ihnen definierten Pfad ausgegeben und in den src-Attributen Ihrer nutzerseitigen img-Elemente referenziert. Die ursprünglichen Dateien bleiben dabei erhalten.

const { src, dest } = require('gulp');
const respimg = require('gulp-responsive');

exports.webp = function() {
  return src('./src-img/*')
    .pipe(respimg({
      '*': [{
        quality: 70,
        format: ['webp', 'jpeg'],
        progressive: true
      }]
  }))
  .pipe(dest('./img/'));
}

Mit einem solchen Prozess würde eine Produktionsumgebung nicht beeinträchtigt werden, wenn jemand im Projektteam versehentlich ein Foto mit einer riesigen Truecolor-PNG-Datei in das Verzeichnis mit den ursprünglichen Bildquellen hinzufügt. Diese Aufgabe sorgt unabhängig von der Codierung des Originalbilds für ein effizientes WebP und ein zuverlässiges JPEG-Fallback im Vollbildverfahren, das sich im Handumdrehen anpassen lässt. Natürlich wird durch diesen Vorgang auch sichergestellt, dass Ihre ursprünglichen Image-Dateien in der Entwicklungsumgebung des Projekts erhalten bleiben. Das bedeutet, dass diese Einstellungen jederzeit angepasst werden können, wobei nur die automatische Ausgabe überschrieben wird.

Wenn Sie mehrere Dateien ausgeben möchten, übergeben Sie mehrere Konfigurationsobjekte – abgesehen vom Hinzufügen eines width-Schlüssels und eines Werts in Pixeln:

const { src, dest } = require('gulp');
const respimg = require('gulp-responsive');

exports.default = function() {
  return src('./src-img/*')
    .pipe(respimg({
    '*': [{
            width: 1000,
            format: ['jpeg', 'webp'],
            progressive: true,
            rename: { suffix: '-1000' }
            },
            {
            width: 800,
            format: ['jpeg', 'webp'],
            progressive: true,
            rename: { suffix: '-800' }
            },
            {
            width: 400,
            format: ['jpeg', 'webp'],
            progressive: true,
            rename: { suffix: '-400' },
        }]
        })
    )
    .pipe(dest('./img/'));
}

Im Beispiel oben war das Originalbild (monarch.png) größer als 3, 3 MB. Die größte durch diese Aufgabe generierte Datei (monarch-1000.jpeg) ist ungefähr 150 KB groß. Die kleinste, monarch-400.web, ist nur 32 KB groß.

[10:30:54] Starting 'default'...
[10:30:54] gulp-responsive: monarch.png -> monarch-400.jpeg
[10:30:54] gulp-responsive: monarch.png -> monarch-800.jpeg
[10:30:54] gulp-responsive: monarch.png -> monarch-1000.jpeg
[10:30:54] gulp-responsive: monarch.png -> monarch-400.webp
[10:30:54] gulp-responsive: monarch.png -> monarch-800.webp
[10:30:54] gulp-responsive: monarch.png -> monarch-1000.webp
[10:30:54] gulp-responsive: Created 6 images (matched 1 of 1 image)
[10:30:54] Finished 'default' after 374 ms

Natürlich sollten Sie die Ergebnisse sorgfältig auf sichtbare Komprimierungsartefakte prüfen oder möglicherweise die Komprimierung erhöhen, um zusätzliche Einsparungen zu erzielen. Da diese Aufgabe nicht destruktiv ist, können diese Einstellungen ganz einfach geändert werden.

Im Gegenzug erhalten Sie als Gegenleistung für die wenigen Kilobyte, die Sie mit sorgfältiger manueller Mikrooptimierung wegnehmen könnten, einen Prozess, der nicht nur effizient, sondern auch resilient ist – ein Tool, das Ihr Wissen über leistungsstarke Bild-Assets nahtlos auf ein gesamtes Projekt anwendet, ohne manuelles Eingreifen erforderlich.

Responsives Bild-Markup in der Praxis

Das Ausfüllen von srcset-Attributen ist in der Regel ein einfacher manueller Prozess, da das Attribut wirklich nur Informationen über die Konfiguration erfasst, die Sie bereits beim Generieren der Quellen vorgenommen haben. In den oben genannten Aufgaben haben wir die Dateinamen und Breitenangaben festgelegt, denen unser Attribut folgen soll:

srcset="filename-1000.jpg 1000w, filename-800.jpg 800w, filename-400.jpg 400w"

Denken Sie daran, dass der Inhalt des Attributs srcset beschreibend und nicht präskriptiv ist. Eine Überlastung eines srcset-Attributs schadet nicht, solange das Seitenverhältnis jeder Quelle einheitlich ist. Ein srcset-Attribut kann den URI und die Breite aller alternativen Schnitte enthalten, die vom Server generiert werden, ohne unnötige Anfragen zu verursachen. Je mehr Quellen wir für ein gerendertes Bild angeben, desto effizienter kann der Browser Anfragen anpassen.

Wie Sie in Responsive Bilder gelernt haben, sollten Sie das Element <picture> verwenden, um das WebP- oder JPEG-Fallback-Muster nahtlos zu verarbeiten. In diesem Fall verwenden Sie das Attribut type zusammen mit srcset.

<picture>
  <source type="image/webp" srcset="filename-1000.webp 1000w, filename-800.webp 800w, filename-400.webp 400w">
  <img srcset="filename-1000.jpg 1000w, filename-800.jpg 800w, filename-400.jpg 400w" sizes="…" alt="…">
</picture>

Wie Sie wissen, erkennen Browser, die WebP unterstützen, den Inhalt des Attributs type und wählen das Attribut srcset dieses <source>-Elements als Liste der möglichen Bilder aus. Browser, die image/webp nicht als gültigen Medientyp erkennen, ignorieren <source> und verwenden stattdessen das Attribut srcset des inneren <img>-Elements.

Bei der Browserunterstützung gibt es noch eine Überlegung: Für Browser, die kein responsives Bild-Markup unterstützen, benötigen Sie trotzdem ein Fallback. Oder es besteht die Gefahr, dass ein Bild fehlerhaft ist, besonders in alten Browserkontexten. Da <picture>, <source> und srcset in diesen Browsern alle ignoriert werden, muss im src-Attribut der inneren <img> eine Standardquelle angegeben werden.

Da das Herunterskalieren eines Bildes visuell nahtlos erfolgt und die JPEG-Codierung allgemein unterstützt wird, ist die größte JPEG-Datei eine sinnvolle Wahl.

<picture>
  <source type="image/webp" srcset="filename-1000.webp 1000w, filename-800.webp 800w, filename-400.webp 400w">
  <img src="filename-1000.jpg" srcset="filename-1000.jpg 1000w, filename-800.jpg 800w, filename-400.jpg 400w" sizes="…" alt="…">
</picture>

sizes ist möglicherweise etwas schwieriger zu handhaben. Wie Sie gelernt haben, ist sizes zwangsläufig kontextabhängig. Sie können das Attribut nur dann darstellen, wenn Sie wissen, wie viel Platz das Bild im gerenderten Layout einnehmen soll. Um möglichst effiziente Anfragen zu erhalten, muss sich zum Zeitpunkt der Anfragen durch den Endnutzer ein korrektes sizes-Attribut im Markup befinden, lange bevor die Stile angefordert wurden, die das Seitenlayout steuern. Wenn sizes vollständig weggelassen wird, stellt dies nicht nur einen Verstoß gegen die HTML-Spezifikation dar, sondern führt auch zu einem Standardverhalten, das sizes="100vw" entspricht. Dadurch wird der Browser darüber informiert, dass dieses Bild nur durch den Darstellungsbereich selbst eingeschränkt wird, sodass die größtmöglichen möglichen Quellen ausgewählt werden.

Wie bei jeder besonders aufwendigen Aufgabe der Webentwicklung wurde eine Reihe von Tools entwickelt, die die handschriftlichen sizes-Attribute abstrahieren. respImageLint ist ein äußerst wichtiges Code-Snippet, mit dem Sie die Genauigkeit Ihrer sizes-Attribute überprüfen und Verbesserungsvorschläge machen können. Es wird als Bookmarklet ausgeführt, d. h. ein Tool, das Sie in Ihrem Browser ausführen und auf die vollständig gerenderte Seite mit Ihren Bildelementen zeigen. In einem Kontext, in dem der Browser das Seitenlayout genau kennt, kann er den Raum, den ein Bild in diesem Layout bei jeder möglichen Größe des Darstellungsbereichs einnehmen soll, nahezu mit Pixel genau erkennen.

Bericht zu responsiven Bildern mit nicht übereinstimmender Größe und Breite.

Ein Tool zum Linting Ihrer sizes-Attribute ist auf jeden Fall nützlich, aber es hat noch mehr Wert als Tool, um sie im Großhandel zu generieren. Wie Sie wissen, ist die srcset- und sizes-Syntax darauf ausgelegt, Anfragen für Bild-Assets visuell nahtlos zu optimieren. Der Standard-Platzhalterwert 100vw von sizes sollte zwar nie in der Produktion verwendet werden, ist jedoch beim Arbeiten am Layout einer Seite in Ihrer lokalen Entwicklungsumgebung absolut sinnvoll. Sobald die Layout-Stile eingerichtet sind, erhältst du durch das Ausführen von respImageLint individuelle sizes-Attribute, die du kopieren und in dein Markup einfügen kannst. Diese Attribute bieten eine viel größere Detailebene als die von Hand geschriebenen Attribute:

Bericht zu responsiven Bildern mit vorgeschlagenen Abmessungen

Bildanfragen, die durch vom Server gerendertes Markup initiiert werden, werden zwar so schnell verarbeitet, dass JavaScript nicht auf Clientseite ein sizes-Attribut generieren kann. Wenn diese Anfragen clientseitig initiiert werden, gilt dies nicht. Mit dem Projekt Lazysizes können Sie beispielsweise Bildanfragen vollständig zurückstellen, bis das Layout eingerichtet ist. Dadurch kann JavaScript unsere sizes-Werte für uns generieren. Das ist sehr praktisch für Sie und eine Garantie dafür, dass Ihren Nutzern möglichst effiziente Anfragen gesendet werden. Bei diesem Ansatz werden jedoch die Zuverlässigkeit des vom Server gerenderten Markups und die in Browser integrierten Geschwindigkeitsoptimierungen einbußen. Wenn diese Anfragen erst gestartet werden, nachdem die Seite gerendert wurde, hat dies einen enormen negativen Einfluss auf deinen LCP-Wert.

Wenn Sie bereits auf ein clientseitiges Rendering-Framework wie React oder Vue angewiesen sind, entstehen Ihnen natürlich Kosten. In diesen Fällen können Ihre sizes-Attribute bei Verwendung von Lazysizes fast vollständig abstrahiert werden. Und noch besser: Wenn sizes="auto" auf Lazy Loading-Bildern einen Konsens gewinnt und native Implementierungen gewonnen werden, wird Lazysizes faktisch zu einem Polyfill für dieses neu standardisierte Browserverhalten.