Neuerungen bei der Angular NgOptimizedImage-Anweisung

Alex Castle
Alex Castle

Vor etwas mehr als einem Jahr hat das Chrome Aurora-Team die Angular-Richtlinie „NgOptimizedImage“ eingeführt. Mit der Richtlinie soll hauptsächlich die Leistung verbessert werden, gemessen an den Core Web Vitals-Messwerten. Häufig verwendete Bildoptimierungen und Best Practices werden in einer nutzerorientierten API gebündelt, die nicht viel komplizierter ist als ein standardmäßiges <img>-Element.

2023 haben wir die directive um neue Funktionen erweitert. In diesem Beitrag werden die wichtigsten dieser neuen Funktionen beschrieben. Dabei liegt der Schwerpunkt darauf, warum wir uns entschieden haben, die einzelnen Funktionen zu priorisieren und wie sie dazu beitragen können, die Leistung von Angular-Anwendungen zu verbessern.

Neue Funktionen

NgOptimizedImage wurde im Laufe der Zeit erheblich verbessert, einschließlich der folgenden neuen Funktionen.

Ausfüllmodus

Das Festlegen der Größe deiner Bilder durch die Angabe eines width- und height-Attributs ist sehr wichtig, um Layoutverschiebungen zu reduzieren. Denn Browser müssen das Seitenverhältnis des Bildes kennen, um Platz dafür zu sparen. Die Größe von Bildern zu ändern, ist jedoch zusätzliche Arbeit für App-Entwickler und macht bei einigen Anwendungsfällen keinen Sinn.

Diese Spannung wird durch die erste wichtige Funktion behoben, die der Bildkomponente nach der Entwicklervorschau hinzugefügt wurde: der Füllungsmodus. So können Entwickler Bilder einschließen, ohne dass die Größe explizit geändert werden muss und ohne dass Layoutverschiebungen auftreten.

Im Füllmodus ist die Anforderung für die Bildgröße deaktiviert und das Bild wird automatisch so gestaltet, dass es das enthaltende Element ausfüllt. Dadurch wird das Seitenverhältnis eines Bildes vom Platz getrennt, den es auf der Seite einnimmt. So haben Sie mehr Kontrolle darüber, wie Bilder in Ihr Seitenlayout passen.

Im Füllmodus wird NgOptimizedImage als leistungsstärkere Alternative zur CSS-Eigenschaft background-image verwendet. Platzieren Sie ein Bild in <div> oder einem anderen Element, das den background-image-Stil hätte, und aktivieren Sie dann den Füllmodus wie im vorherigen Codebeispiel gezeigt. Mit den CSS-Eigenschaften object-fit und object-position auf der <div> können Sie festlegen, wie das Bild im Hintergrund positioniert wird.

// Height and width are required
<img ngSrc="example.com" height="300" width="400">

// Unless you use fill mode!
<div style="width: 100vw; height: 50em; position: relative">
  <img ngSrc="example.com" fill>
</div>

Srcset-Generierung

Eine der effektivsten Methoden zur Bildoptimierung ist die Verwendung des Attributs srcset, um dafür zu sorgen, dass für jedes Gerät, das auf Ihre Anwendung zugreift, Bilder in der richtigen Größe heruntergeladen werden. Wenn du srcset in deiner App verwendest, kannst du Bandbreite vermeiden und deinen LCP Core Web Vitals-Wert erheblich verbessern.

Der Nachteil des Attributs srcset ist, dass die Implementierung mühsam sein kann. Wenn Sie srcset-Werte manuell eingeben, müssen Sie jedem Bildelement in Ihrer App mehrere Zeilen Markup mit mehreren benutzerdefinierten URLs für jeden srcset hinzufügen. Außerdem müssen Sie eine Reihe von Wendepunkten festlegen. Das ist schwierig, da sie sowohl die Bildschirmdichten als auch die Darstellungsbereiche gängiger Geräte darstellen können.

Deshalb war die automatische Erstellung von Srcset-Dateien in der NgOptimizedImage-Direktive ein wichtiger Meilenstein nach der Einführung. Durch diese Ergänzung kann jede Anwendung, die ein CDN verwendet und die Bildgröße unterstützt, alle mit der NgOptimizedImage-Anweisung generierten "srcsets" vollständig und anpassbar automatisch hinzufügen.

Wir haben eine vereinfachte API zum Festlegen des Attributs sizes hinzugefügt, mit der sichergestellt wird, dass jedes Bild den richtigen srcset-Typ erhält. Wenn Sie kein sizes-Attribut angeben, wissen wir, dass das Bild eine feste Größe haben soll und ein dichteabhängiges „srcset“ erhalten sollte, z. B.:

<img src="www.example.com/image.png" srcset="www.example.com/image.png?w=400 1x, www.example.com/image.png?w=800 2x" >

Diese Art von srcset sorgt dafür, dass Bilder in einer Größe bereitgestellt werden, die die Pixeldichte des Geräts des Nutzers berücksichtigt.

Wenn Sie jedoch das Attribut sizes angeben, generiert NgOptimizedImage mithilfe der folgenden Standardliste von Haltepunkten ein responsives srcset, das Haltepunkte für viele gängige Geräte- und Bildgrößen enthält:

[16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840]

Generierung von Preconnects

Um den LCP zu verbessern, ist es wichtig, die Zeit zu verkürzen, die Nutzer für das Herunterladen des LCP-Bildes benötigen. Im vorherigen Abschnitt haben Sie gesehen, wie srcset bei der Übertragung kleinerer Bilddateien helfen kann. Eine ebenso wichtige Optimierung besteht darin, die Übertragung so schnell wie möglich zu starten. Eine Möglichkeit dazu ist die Verwendung von link rel="preconnect"-Tags, um die Verbindung zu Ihrer Bilddomain zu starten.

NgOptimizedImage warnt schon immer, wenn Sie keine Vorabverbindung zur Domain Ihres LCP-Bildes herstellen. Eine Warnung ist jedoch nicht die ideale Lösung. Wir würden das Problem lieber direkt für Sie beheben. Und genau das macht NgOptimizedImage jetzt mit der automatischen Generierung von Preconnects.

Zur Unterstützung dieser Funktion versuchen wir, mithilfe der statischen Codeanalyse Bilddomains in NgOptimizedImage-Ladeprogrammen zu erkennen und automatisch Preconnect-Link-Tags für diese Domains zu generieren. Es gibt Fälle, in denen manuelle Vorverbindungslinks erforderlich sind. Für die meisten Nutzer bedeutet die automatische Vorverbindung jedoch einen Schritt weniger, der für eine gute Bildleistung erforderlich ist.

Erweiterte Unterstützung für benutzerdefinierte Lader

Ein Schlüsselelement von NgOptimizedImage ist die Loader-Architektur, mit der die Anweisung automatisch URLs generieren kann, die auf das CDN des Anwendungsbildes zugeschnitten sind. Für gängige CDNs sind mehrere integrierte Loader enthalten. Außerdem ist die Verwendung von benutzerdefinierten Ladern möglich, mit denen Sie NgOptimizedImage in nahezu jede Lösung für das Hosten von Bildern einbinden können.

Bei der Einführung waren diese benutzerdefinierten Lader nur eingeschränkt nutzbar und konnten nur das width-Attribut aus dem Bildelement lesen. Aufgrund von Nutzerfeedback haben wir die Unterstützung für eine anpassbare loaderParams-Datenstruktur hinzugefügt, mit der beliebige Daten vom Bildelement an den benutzerdefinierten Lader übergeben werden können. Mit der Erweiterung können benutzerdefinierte Lader so einfach oder komplex sein, wie es die Bildinfrastruktur einer Anwendung erfordert.

Das folgende Beispiel zeigt, wie ein einfaches benutzerdefiniertes Ladeprogramm mit der loaderParams API zwischen zwei alternativen Bilddomains auswählen könnte:

const myCustomLoader = (config: ImageLoaderConfig) => {
  if (config.loaderParams?.alternateDomain) {
    return `https://alternate.domain.com/images/${config.src}`
  }
  return `https://primary.domain.com/images/${config.src}`;
};

Ein Beispiel für einen komplexeren benutzerdefinierten Loader finden Sie in der Angular-Dokumentation.

Erweiterte Hinweise zur Bildleistung

Bisher waren alle Benachrichtigungen zur Bildleistung, die wir Angular hinzugefügt haben, Teil der Direktive „NgOptimizedImage“. Wenn Sie die Richtlinie nicht in der App verwenden, erhalten Sie keine Informationen zu Problemen mit der Bildleistung.

In Angular 17 werden die Empfehlungen zur Bildleistung auf alle Angular-Apps ausgeweitet. Wenn wir Bildmuster erkennen, die wir als leistungsmindernd einstufen, z. B. das Lazy-Loading Ihres LCP-Bilds oder das Herunterladen einer Datei, die viel zu groß für die Seite ist, werden wir Sie benachrichtigen, auch wenn Sie NgOptimizedImage nicht verwenden.

Die Bildleistung ist für alle Apps wichtig. Wir freuen uns, weiterhin Sicherheitsmaßnahmen zu entwickeln, um häufige Fehler in Angular-Apps zu vermeiden.

Aussichten

Wir arbeiten bereits an der nächsten Reihe von Funktionen für NgOptimizedImage. Die Bildleistung bleibt unser zentrales Anliegen. Wir möchten aber auch Funktionen hinzufügen, die die Entwicklerfreundlichkeit verbessern, damit NgOptimizedImage weiterhin eine attraktive Option für das Einfügen von Bildern in Angular-Anwendungen bleibt.

Eine Funktion, die für uns Priorität hat, sind Bildplatzhalter. Sie werden häufig verwendet, um das Laden von Bildern in Webanwendungen zu verbessern. Bei falscher Implementierung können sie jedoch die Leistung beeinträchtigen. Wir hoffen, in NgOptimizedImage ein leistungsorientiertes Bildplatzhaltersystem einbinden zu können. Weitere Ankündigungen findest du in unserem Blog.