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 sprawdzone metody w interfejsie API przeznaczonym dla użytkowników, który nie jest dużo bardziej skomplikowany niż standardowy element <img>
.
W 2023 r. wzbogaciliśmy directive o nowe funkcje. W tym poście opisujemy najważniejsze z tych nowych funkcji, wyjaśniając, dlaczego postanowiliśmy nadać każdej z nich priorytet oraz jak mogą one pomóc zwiększyć wydajność aplikacji Angular.
Nowe funkcje
Z czasem funkcja ngOptimizedImage znacznie się ulepsza, co obejmuje te nowe funkcje.
Tryb wypełniania
Dostosowywanie rozmiaru obrazów za pomocą atrybutów width
i height
to niezwykle ważna optymalizacja w celu ograniczenia przesunięcia układu, ponieważ przeglądarki muszą znać współczynnik proporcji obrazu, aby zaoszczędzić na nim 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ą dołączać 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 współczynnik proporcji obrazu zostanie oddzielony od zajmowanego przez niego miejsca na stronie i zapewni większą kontrolę nad dopasowaniem obrazów 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
Jedna z najskuteczniejszych technik optymalizacji obrazów to zastosowanie atrybutu srcset
, aby mieć pewność, że obrazy o prawidłowym rozmiarze będą pobierane z każdego urządzenia, na którym użytkownik korzysta z aplikacji. Korzystanie z interfejsu srcset
w całej aplikacji pozwala uniknąć marnowania przepustowości i znacznie poprawić podstawowy wskaźnik internetowy LCP.
Wadą atrybutu srcset
jest to, że jego wdrożenie może być uciążliwe. 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 typowych urządzeniach.
Dlatego dodanie automatycznego generowania zestawu src do dyrektywy 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" >
Ten rodzaj atrybutu srcset sprawia, że obrazy są wyświetlane w rozmiarze uwzględniającym gęstość pikseli na ekranie urządzenia użytkownika.
Z drugiej strony, jeśli dodasz właściwość sizes
, NgOptimizedImage
wygeneruje elastyczny atrybut srcset zawierający punkty przerwania dla wielu typowych rozmiarów urządzeń i obrazów, korzystając z tej domyślnej listy punktów przerwania:
[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ć na przykład za pomocą tagów link rel="preconnect"
, aby szybko rozpocząć połączenie z domeną obrazu.
Od samego początku NgOptimizedImage wysyła ostrzeżenie, 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 elementach ładujących NgOptimizedImage i automatycznie generować dla nich tagi linków w ramach wstępnego połączenia. Nadal mogą być wymagane ręczne wstępne połączenia, ale w przypadku większości użytkowników takie automatyczne łączenie oznacza o jeden krok mniej, by uzyskać dobrą wydajność 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 na rynek te niestandardowe moduły ładowania miały ograniczony zakres i mogły odczytywać tylko atrybut width
z elementu graficznego. W odpowiedzi na opinie użytkowników dodaliśmy obsługę konfigurowalnej struktury danych loaderParams
, która umożliwia przekazywanie dowolnych danych z elementu graficznego do niestandardowego programu wczytującego. 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 Angular 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 Angular 17 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 w przypadku wszystkich aplikacji, dlatego nadal pracujemy nad dodatkowych zabezpieczeń, które pomogą zapobiegać typowym błędom w aplikacjach Angular.
Pozdrawiam
Pracujemy już nad kolejnym zestawem funkcji NgOptimizedImage. Choć wydajność obrazów pozostaje naszym głównym zagadnieniem, chcemy też dodać funkcje, które poprawią wrażenia programistów, aby mieć pewność, że NgOptimizedImage pozostanie atrakcyjną opcją umieszczania 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 szybszego wczytywania obrazów w aplikacjach internetowych, ale mogą negatywnie wpływać na 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 stawiał na pierwszym miejscu wydajność. Więcej informacji znajdziesz na naszym blogu.