Łatwe tworzenie obrazów w wysokiej rozdzielczości

Ekrany o dużej gęstości pikseli szybko stają się normą. Twórcy treści muszą się do tego dostosować. Oto krótki przewodnik, który pomoże Ci wyświetlać w internecie obrazy wysokiej jakości bez stosowania polyfillów, JavaScriptu, hacków CSS i funkcji przeglądarki, które nie zostały jeszcze wdrożone. Jednym słowem: bez drastycznej zmiany procesu.

Obecnie jest wiele propozycji obrazów elastycznych, z których wiele wiąże się ze znacznymi zmianami dla programistów stron internetowych. Implementacja atrybutu standardowa (standardowa) srcset <img> jest trudna do wdrożenia, zwłaszcza przy złożonym wyborze w usłudze srcset na podstawie widocznego obszaru:

banner-HD.jpeg 2x, banner-phone.jpeg 100w, banner-phone-HD.jpeg 100w 2x

Mimo że właściwość CSS image-set używa tylko atrybutu devicePixelRatio do określenia, który obraz ma być wczytany, zmusza ona deweloperów do napisania dodatkowej znaczniki dla każdego obrazu.

Inne propozycje, takie jak element <picture>, są jeszcze bardziej szczegółowe. Co więcej, nie są one zgodne ze standardami, więc ich powszechna dostępność jest jeszcze bardziej ograniczona niż w przypadku atrybutu srcset. Jedyną alternatywą są JavaScript i rozwiązania po stronie serwera. Jednak mają one wady, o których mowa w innych artykułach.

W tym artykule omówimy różne zastosowania obrazów często spotykanych w internecie i zaproponujemy proste rozwiązania działające zarówno na ekranach o dużej gęstości pikseli, jak i na urządzeniach zwykłych. W ramach tej dyskusji każde urządzenie, które podaje wartość window.devicePixelRatio większą niż 1, może być uznawane za urządzenie o wysokiej rozdzielczości, ponieważ oznacza to, że piksele CSS nie są takie same jak piksele urządzenia i że obrazy są powiększane.

Podsumowanie:

  • W miarę możliwości używaj CSS/SVG zamiast obrazów rastrowych.
  • Domyślnie używaj obrazów zoptymalizowanych pod kątem wyświetlaczy o dużej gęstości.
  • Używaj plików PNG do prostych rysunków i grafiki pikseli (np. logo).
  • W przypadku obrazów o wielu kolorach (np. zdjęć) używaj skompresowanych plików JPEG.
  • Zawsze ustawiaj konkretne rozmiary (za pomocą CSS lub HTML) we wszystkich elementach graficznych.

Proste rysunki i pikselowa grafika

Małych obrazów można często uniknąć, korzystając z funkcji CSS lub SVG. Nie trzeba np. używać obrazów w przypadku zaokrąglonych rogów, ponieważ właściwość CSS border-radius jest powszechnie obsługiwana. Podobnie, czcionki niestandardowe są powszechnie obsługiwane, więc nie zalecamy używania tekstu „obrazkowego”.

W niektórych przypadkach (np. w przypadku logo) jedynym sposobem postępowania może być użycie obrazu. Na przykład logo Chrome ma naturalny rozmiar 256 x 256. Na wyświetlaczu Retina widać aliasy linii na ukośnych i krzywych krzywych, co wygląda na grubsze i niezbyt dobrze, zwłaszcza w porównaniu z wyraźnie renderowanym tekstem:

Chrome 1x
PNG 1x

Wymiary naturalne: 256x256px, rozmiar zasobu: 31 kB, format: PNG

Przekonany? Cieszę się. Teraz użyjmy obrazu o dużej gęstości. Zapisywanie logo w formacie JPEG może być kuszące, ponieważ zapisywanie logo i innej grafiki w formacie stratnym powoduje często występowanie artefaktów. W tym przypadku problem został wyolbrzymiony przez bardzo wysokie skompresowanie, ale zwróć uwagę na pasy na gradientach, plamki na białym tle i niechlujne linie:

Chrome 2x
Jpeg 2x

Wymiary naturalne: 512x512px, rozmiar zasobu: 13 kB, format: JPEG

W przypadku stosunkowo małych obrazów należy użyć 2 plików PNG. Pamiętaj, że różnica w rozmiarze między 1x a 2x PNG jest zwykle dość duża (w tym przypadku 52 kB). W przypadku logo jest to jednak twarz Twojej witryny i pierwsza rzecz, którą zobaczą użytkownicy. Jeśli z założenia zrezygnujesz z jakości na rzecz rozmiaru, Twoi użytkownicy zobaczą też ostatnią rzecz.

Oto logo Chrome w całej okazałości, w pomniejszonej do połowy wielkości wersji dostosowanej do wyświetlaczy 2x:

Chrome 2x
PNG 2x

Wymiary naturalne: 512x512px, rozmiar komponentu: 83 kB, format: PNG

Znaczniki do renderowania powyższego są następujące:

<img src="chrome2x.png" style="width: 256px; height: 256px;"/>

Zwróć uwagę, że na obrazie podałem szerokość i wysokość. Jest to konieczne, ponieważ naturalny rozmiar obrazu to 512 pikseli. Dobrze radzi sobie też z wydajnością, ponieważ mechanizm renderowania dobrze rozumie rozmiar elementu i nie musi zbyt ciężko go obliczyć.

Jednym z możliwych sposobów optymalizacji jest zmniejszenie 24-bitowego pliku PNG do 8-bitowego z paletą. Ta metoda sprawdza się w przypadku obrazów o małej liczbie kolorów, w tym logo Chrome. Aby to zrobić, możesz użyć narzędzia takiego jak http://pngquant.org/. Widać tu trochę pasów, ale ten plik ma tylko 13 kB – to aż 6 razy większa oszczędność w porównaniu do oryginalnego pliku PNG o wymiarach 512 x 512.

Chrome 2x 8-bit
PNG 2x 8-bitowy

Wymiary naturalne: 512x512px, rozmiar zasobu: 13 kB, format: PNG, 8-bit palette

Obrazy w różnych kolorach

Napisałem artykuł w HTML5Rocks, w którym omawiał kilka różnych technik tworzenia elastycznych obrazów. Przeprowadziłem też badania nad kompresowaniem plików JPEG 1x i 2x oraz porównaniem ich rozmiarów i jakości wizualnej. Oto jeden taki kafelek z powyższego artykułu:

Kafelek.

Opisałam obrazy według poziomu kompresji (na co wskazuje jakość JPEG), rozmiaru (w bajtach) i mojej subiektywnej opinii na temat ich porównywalnej jakości wizualnej (wg liczb). Co ciekawe, mocno skompresowany obraz 2x (oznaczony 3) jest mniejszy i wygląda lepiej niż nieskompresowany obraz 1x (oznaczony 4). Innymi słowy, między obrazami 4–3 zdołaliśmy poprawić jakość obrazu, podwajając każdy wymiar i znacznie zwiększając kompresję, a jednocześnie zmniejszając rozmiar o 2 kB.

Kompresja, wymiary i jakość obrazu

Chcę dowiedzieć się więcej o zależnościach między poziomem kompresji, wymiarami obrazu, jakością obrazu i rozmiarem obrazu. Na podstawie powyższego badania przeprowadziłem badanie z taką hipotezą:

Hipoteza

Przy wystarczającym stopniu kompresji obraz w rozmiarach 2 x będzie wyglądał tak samo jak obraz w rozmiarze 1 x przy innej (niższej) kompresji. W tym przypadku jednak skompresowany obraz 2x będzie mniejszy niż obraz 1x.

Przetwarzanie

  • Mając obraz 2x, wygeneruj obraz 1x.
  • Kompresuj oba obrazy na różnych poziomach.
  • Utwórz stronę testową, na której obok siebie wyświetlają się oba zestawy obrazów.
  • Znajdź w obu zestawach miejsce, w którym obrazy są identyczne.
  • Zwróć uwagę na porównywalne rozmiary obrazów i poziomy kompresji.
  • Wypróbuj na wyświetlaczu 1x i 2x.

Stworzyłem aplikację do porównywania obrazów obok siebie, podobną do widoku porównawczego w Lightroom. Chodzi o to, aby obok siebie wyświetlić obrazy w powiększeniu 1x i 2x, ale też umożliwić powiększenie dowolnej sekcji obrazu, aby uzyskać więcej szczegółów. Możesz też wybrać format JPEG lub WebP i zmienić jakość kompresji, aby porównać rozmiar pliku i jakość obrazu. Chodzi o to, aby dostosować ustawienia kilku obrazów, określić, jakie kompromisy w zakresie jakości kompresji, skalowania i formatu są dla Ciebie odpowiednie, a następnie zastosować te ustawienia do wszystkich obrazów.

Zrzut ekranu z porównaniem

Samo narzędzie jest dostępne do wypróbowania. Możesz powiększyć obraz, wybierając jego podrzędny obszar.

Analiza

Na wstępie powiem, że jakość obrazu jest sprawą subiektywną. Poza tym konkretny przypadek użycia prawdopodobnie określi, jakie są Twoje priorytety w zakresie wierności obrazu i rozmiaru pliku. Dodatkowo różne rodzaje funkcji obrazu reagują inaczej na jakość skalowania i kompresji, więc uniwersalne rozwiązanie niekoniecznie może się tu sprawdzić. Celem tego narzędzia jest pomoc w rozwinięciu intuicji dotyczącej jakości obrazu, kompresji, skali i formatów.

Po zabawie z powiększeniem obrazu szybko zauważyłem kilka rzeczy. Po pierwsze, wolę obrazy quality=30 dpr=2x niż quality=90 dpr=1x, ponieważ są one bardziej szczegółowe. Rozmiar tych obrazów również jest porównywalny (w przypadku płaskiego obrazu skompresowany obraz 2x ma 76 KB, a nieskompresowany obraz 1x – 80 kB).

Wyjątkiem od tej reguły są obrazy z gradientami, które są bardzo skompresowane (quality<30). Zdjęcia te często mają pasy kolorów, które są równie niekorzystne niezależnie od skali obrazu. Przykładem są próbki ptaków i samochodów dostępne w narzędziu.

Obrazy WebP wyglądają o wiele wyraźniej niż JPEG, zwłaszcza na niskim poziomie kompresji. Pasy kolorów są znacznie mniej widoczne. I na koniec: obrazy WebP są znacznie bardziej zwarte.

Zastrzeżenia i podsumowanie

Dbanie, by obrazy dobrze wyglądały na wyświetlaczach o dużej gęstości to tylko połowa problemów związanych z obrazami, spowodowanych dużą zmiennością ekranów. W niektórych przypadkach możesz chcieć wyświetlać zupełnie różne obrazy w zależności od rozmiaru widocznego obszaru. Na przykład zdjęcie profilowe Obamy może być odpowiednie na ekran telefonu, ale stojak przed nim i flaga za nim mogą lepiej pasować do ekranu laptopa.

Celowo unikałem tematu „kierunku sztuki”, skupiając się tylko na obrazach o wysokiej rozdzielczości. Ten problem można rozwiązać na kilka różnych sposobów: za pomocą definicji media, obrazów tła, kodu JavaScript, nowych funkcji, takich jak image-set, lub na serwerze. Ten temat jest omawiany w artykule Obrazy o wysokiej rozdzielczości w przypadku zmiennej gęstości pikseli.

Zakończę z kilkoma nierozstrzygniętymi problemami:

  • Wpływ wysokiej kompresji na wydajność. Jakie są konsekwencje dekodowania bardzo skompresowanych obrazów?
  • Jakie są konsekwencje konieczności zmniejszenia rozmiaru obrazu, gdy wczytujemy obraz 2x na wyświetlaczu 1x?

Podsumowując, zamiast obrazów rastrowych wybierz CSS i SVG. Jeśli obrazy rastrowe są wymagane, użyj formatu PNG w przypadku obrazów z ograniczoną paletą i wieloma jednolitymi kolorami oraz formatu JPEG w przypadku obrazów z wieloma kolorami i gradientami. Najlepsze w tym podejściu jest to, że znaczniki pozostają praktycznie niezmienione. Programista stron internetowych musi tylko wygenerować 2 razy więcej zasobów i odpowiednio dopasować rozmiar obrazów w modelu DOM.

Aby dowiedzieć się więcej, zapoznaj się z artykułem Scotta Jehla na podobny temat. Życzymy Ci ostrych obrazów i niskiego zużycia danych komórkowych.