Nieco ponad rok temu zespół Chrome Aurora wprowadził dyrektywę NgOptimizedImage w Angularze. Dyrektywa koncentruje się przede wszystkim na poprawie wydajności, mierzonej za pomocą podstawowych wskaźników internetowych. Zawiera ono typowe optymalizacje obrazów i zalecane metody działania w interfejsie API dla użytkowników, który nie jest dużo bardziej skomplikowany niż standardowy element <img>
.
W 2023 r. wzbogaciliśmy dyrektywę o nowe funkcje. W tym poście opisujemy najważniejsze z tych nowych funkcji, z uwzględnieniem tego, dlaczego zdecydowaliśmy się nadać priorytety poszczególnym funkcjom i jak mogą one poprawić wydajność aplikacji Angular.
Nowe funkcje
Z czasem funkcja ngOptimizedImage znacznie się ulepsza, co obejmuje te nowe funkcje.
Tryb wypełniania
Ustawianie rozmiaru obrazów przez podanie atrybutu width
i height
jest bardzo ważną optymalizacją, która pozwala zmniejszyć zmianę układu, ponieważ przeglądarki muszą znać format obrazu, aby zarezerwować dla niego miejsce. Jednak dostosowanie rozmiaru obrazów to dodatkowa praca dla programistów aplikacji, a w niektórych przypadkach nie ma to sensu.
Rozwiązaniem tego problemu jest pierwsza ważna funkcja dodana do komponentu obrazu po wersji dla deweloperów: tryb wypełnienia. Dzięki temu deweloperzy mogą dodawać obrazy bez konieczności określania ich rozmiarów i zmiany układu.
W trybie wypełnienia wymagania dotyczące rozmiaru obrazu są wyłączone, a obraz jest automatycznie stylizowany tak, aby wypełniał element, w którym się znajduje. Dzięki temu format obrazu jest niezależny od zajmowanej przez niego przestrzeni na stronie i masz większą kontrolę nad tym, jak obrazy pasują do układu strony.
Tryb wypełniania używa obiektu NgOptimizedImage jako lepszej alternatywy dla właściwości background-image
w CSS. Umieść obraz wewnątrz elementu <div>
lub innego elementu, który miałby styl background-image
, a następnie włącz tryb wypełnienia, jak pokazano w poprzednim przykładzie kodu. Użyj właściwości CSS object-fit
i object-position
w elemencie <div>
, aby określić położenie obrazu na tle.
// 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>
Generowanie srcset
Jedną z najskuteczniejszych technik optymalizacji obrazów jest użycie atrybutu srcset
, aby zapewnić pobieranie obrazów o odpowiednich rozmiarach na dowolne urządzenie, które uzyskuje dostęp do aplikacji. Korzystanie z funkcji srcset
w aplikacji może zapobiec marnowaniu przepustowości i znacznie poprawić wskaźnik LCP Core Web Vital.
Wadą atrybutu srcset
jest to, że może być on trudny do wdrożenia. Ręczne wpisywanie wartości srcset
oznacza dodanie wielu linii znaczników do każdego elementu obrazu w aplikacji wraz z wieloma niestandardowymi adresami URL dla każdego srcset
. Musisz też określić zestaw punktów granicznych, co jest skomplikowane, ponieważ mogą one reprezentować zarówno gęstość ekranu, jak i rozmiary widocznego obszaru na różnych urządzeniach.
Dlatego dodanie automatycznego generowania zestawu src w instrukcji NgOptimizedImage było ważnym krokiem po wprowadzeniu na rynek. Dzięki temu każda aplikacja korzystająca z CDN obsługującego zmianę rozmiaru obrazu może automatycznie dodawać do każdego obrazu wygenerowanego za pomocą dyrektywy NgOptimizedImage pełne, konfigurowalne zestawy srcset.
Dodaliśmy uproszczony interfejs API do ustawiania właściwości sizes
, która służy do zapewnienia, że każde zdjęcie ma odpowiedni typ srcset
. Jeśli nie podasz atrybutu sizes
, będziemy wiedzieć, że obraz ma mieć rozmiar stały i że należy użyć zestawu src zależnego od gęstości, takiego jak ten:
<img src="www.example.com/image.png" srcset="www.example.com/image.png?w=400 1x, www.example.com/image.png?w=800 2x" >
Takie ustawienie srcset zapewnia, że obrazy są wyświetlane w rozmiarze uwzględniającym gęstość pikseli na urządzeniu użytkownika.
Jeśli jednak uwzględnisz właściwość sizes
, NgOptimizedImage
wygeneruje elastyczny zestaw src, który zawiera punkty graniczne dla wielu typowych urządzeń i rozmiarów obrazów, korzystając z tej domyślnej listy punktów granicznych:
[16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840]
Generowanie wstępnego połączenia
Aby poprawić LCP, należy skrócić czas pobierania obrazu LCP przez użytkowników. W poprzedniej sekcji pokazaliśmy, jak srcset
może pomóc w przesyłaniu mniejszych plików z obrazami, ale równie ważna jest optymalizacja polegająca na jak najszybszym rozpoczęciu przesyłania. Możesz to zrobić, używając tagów link rel="preconnect"
, aby szybko nawiązać połączenie z domeną obrazu.
Od samego początku NgOptimizedImage ostrzega, jeśli nie uda Ci się nawiązać połączenia z domeną obrazu LCP, ale ostrzeżenie nie jest idealnym rozwiązaniem – wolimy po prostu rozwiązać problem za Ciebie. I właśnie to robi teraz NgOptimizedImage dzięki automatycznemu generowaniu wstępnego połączenia.
Aby obsługiwać tę funkcję, używamy analizy kodu stałego, aby wykrywać domeny obrazów w ładowarkach NgOptimizedImage i automatycznie generować tagi linków w ramach wstępnego połączenia dla tych domen. W niektórych przypadkach nadal konieczne jest ręczne łączenie wstępne, ale dla większości użytkowników automatyczne łączenie wstępne oznacza o jeden krok mniej do uzyskania dobrej jakości obrazu.
Ulepszona obsługa niestandardowych ładowarek
Kluczowym elementem dyrektywy NgOptimizedImage jest architektura ładowarki, która umożliwia automatyczne generowanie adresów URL dostosowanych do CDN obrazu aplikacji. Zawiera zestaw wbudowanych ładowarek dla powszechnie używanych sieci CDN. Zapewniamy też możliwość korzystania z niestandardowych ładowarek, które umożliwiają integrację NgOptimizedImage z prawie każdym rozwiązaniem do hostowania obrazów.
W momencie wprowadzenia te niestandardowe ładowarki miały ograniczony zakres działania i mogły odczytywać tylko atrybut width
z elementu obrazu. W odpowiedzi na opinie użytkowników dodaliśmy obsługę dostosowywalnej struktury danych loaderParams
, która umożliwia przekazywanie dowolnych danych z elementu obrazu do niestandardowego ładowarki. Dzięki rozszerzeniu ładowarki niestandardowe mogą być tak proste lub tak złożone, jak wymaga tego infrastruktura aplikacji.
Ten przykład pokazuje, jak prosty niestandardowy ładownik może używać interfejsu API loaderParams
do wyboru jednej z 2 alternatywnych domen obrazów:
const myCustomLoader = (config: ImageLoaderConfig) => {
if (config.loaderParams?.alternateDomain) {
return `https://alternate.domain.com/images/${config.src}`
}
return `https://primary.domain.com/images/${config.src}`;
};
Przykład bardziej złożonego niestandardowego ładownika znajdziesz w dokumentacji Angulara.
Rozwinięte wskazówki dotyczące skuteczności obrazów
Do tej pory każdy alert dotyczący wydajności obrazu dodany do Angulara był częścią dyrektywy NgOptimizedImage. Jeśli nie używasz dyrektywy w aplikacji, nie otrzymasz żadnych wskazówek dotyczących problemów z wydajnością obrazu.
W wersji 17 Angulara rozszerzamy zakres wskazówek dotyczących wydajności obrazów, aby obejmował wszystkie aplikacje Angular. Jeśli wykryjemy wzorce obrazów, które są błędami wpływającymi na wydajność, np. opóźnione wczytywanie obrazu LCP lub pobieranie pliku, który jest zbyt duży dla strony, powiadomimy Cię o tym, nawet jeśli nie używasz funkcji NgOptimizedImage.
Wydajność obrazu jest ważna dla wszystkich aplikacji, dlatego z przyjemnością kontynuujemy tworzenie zabezpieczeń, które pomogą uniknąć typowych błędów w aplikacjach Angular.
Pozdrawiam
Pracujemy już nad kolejnym zestawem funkcji NgOptimizedImage. Chociaż wydajność obrazów pozostaje naszym głównym celem, chcemy też dodać funkcje, które ułatwią pracę deweloperom i spowodują, że NgOptimizedImage pozostanie atrakcyjną opcją dołączania obrazów w aplikacjach Angular.
Jedną z funkcji, które są dla nas priorytetowe, są obiekty zastępcze obrazów. Są one często używane do ładowania obrazów w aplikacjach internetowych, ale mogą obniżać wydajność, jeśli są niewłaściwie zaimplementowane. Mamy nadzieję, że uda nam się stworzyć w ramach NgOptimizedImage system obiektów zastępczych obrazu, który będzie kładł nacisk na wydajność. Aby dowiedzieć się więcej, czytaj nasz blog.