Obrazy w wysokiej rozdzielczości dla zmiennej gęstości pikseli

Jedną z cech współczesnych złożonych urządzeń jest dostępność bardzo szerokiej gamy gęstości pikseli na ekranie. Niektóre urządzenia mają wyświetlacze o bardzo wysokiej rozdzielczości, podczas gdy inne są w tym aspekcie gorsze. Deweloperzy aplikacji muszą obsługiwać różne gęstości pikseli, co może być dość trudne. W przypadku internetu mobilnego problemy te są potęgowane przez kilka czynników:

  • duża różnorodność urządzeń o różnych formatach.
  • Ograniczona przepustowość sieci i żywotność baterii.

W przypadku obrazów celem deweloperów aplikacji internetowych jest wyświetlanie obrazów najwyższej jakości w jak najbardziej efektywny sposób. Z tego artykułu dowiesz się, jak to zrobić już teraz i w najbliższej przyszłości.

W miarę możliwości unikaj obrazów

Zanim otworzysz tę pułapkę na muchy, pamiętaj, że w internecie jest wiele zaawansowanych technologii, które są w dużej mierze niezależne od rozdzielczości i DPI. W szczególności tekst, SVG i duża część CSS będą „działać” dzięki funkcji automatycznego skalowania pikseli w internecie (za pomocą devicePixelRatio).

Nie zawsze jednak można uniknąć obrazów rastrowych. Możesz np. otrzymać zasoby, które trudno byłoby odtworzyć w czystym formacie SVG/CSS, lub masz do czynienia ze zdjęciem. Możesz automatycznie przekonwertować obraz na SVG, ale wektoryzacja zdjęć ma niewielki sens, ponieważ powiększone wersje zwykle nie wyglądają dobrze.

Tło

Bardzo krótka historia gęstości wyświetlania

W początkach wyświetlacze komputerów miały gęstość pikseli 72 lub 96 dpi (punktów na cal).

Gęstość pikseli na wyświetlaczach stopniowo się zwiększa, głównie ze względu na zastosowanie w telefonach komórkowych, w których przypadku użytkownicy zwykle trzymają telefony bliżej twarzy, co sprawia, że piksele są bardziej widoczne. W 2008 roku telefony o rozdzielczości 150 dpi były nową normą. Trend zwiększania gęstości pikseli na ekranie się utrzymał, a dzisiejsze nowe telefony mają ekrany o rozdzielczości 300 dpi (nazwanej przez Apple „Retina”).

Świętym Graalem jest oczywiście wyświetlacz, w którym piksele są całkowicie niewidoczne. W przypadku telefonów obecna generacja wyświetlaczy Retina i HiDPI może być do tego zbliżona. Nowe kategorie sprzętu i urządzeń do noszenia, takie jak Project Glass, będą jednak nadal zwiększać gęstość pikseli.

W praktyce obrazy o niskiej gęstości powinny wyglądać tak samo na nowych ekranach jak na starych, ale w porównaniu z ostrą grafiką o wysokiej gęstości, do której użytkownicy są przyzwyczajeni, obrazy o niskiej gęstości wyglądają dziwnie i pikselatowo. Poniżej przedstawiamy przybliżone symulacje wyglądu obrazu w rozdzielczości 1x na wyświetlaczu w rozdzielczości 2x. Zdjęcie w rozdzielczości 2 x wygląda za to całkiem nieźle.

Baboon 1x
Baboon 2x
Baboons! na ekranach o różnej gęstości pikseli.

Piksele w internecie

Gdy tworzono sieć, 99% wyświetlaczy miało rozdzielczość 96 dpi (lub udawało, że ma taką rozdzielczość), a w tym zakresie przewidziano niewiele wyjątków. Ze względu na duże zróżnicowanie rozmiarów i gęstości ekranów potrzebowaliśmy standardowego sposobu na to, aby obrazy dobrze wyglądały na różnych ekranach o różnych gęstościach i wymiarach.

Specyfikacja HTML rozwiązała ten problem, definiując piksel referencyjny, którego producenci używają do określania rozmiaru piksela CSS.

Korzystając z pikselu referencyjnego, producent może określić rozmiar fizycznego piksela urządzenia w stosunku do piksela standardowego lub idealnego. Ten współczynnik nazywa się współczynnikiem pikseli urządzenia.

Obliczanie współczynnika pikseli urządzenia

Załóżmy, że telefon ma ekran o fizycznym rozmiarze piksela 180 pikseli na cal (ppi). Obliczenie współczynnika pikseli urządzenia obejmuje 3 kroki:

  1. Porównaj rzeczywistą odległość, w której trzymane jest urządzenie, z odległością dla piksela referencyjnego.

    Zgodnie ze specyfikacją wiemy, że przy 28 cali idealnie sprawdza się 96 pikseli na cal. Ponieważ jednak jest to smartfon, użytkownicy trzymają go bliżej twarzy niż laptopa. Szacujemy, że odległość wynosi 18 cali.

  2. Aby uzyskać idealną gęstość pikseli dla danej odległości, pomnóż współczynnik odległości przez standardową gęstość pikseli (96 ppi).

    idealPixelDensity = (28/18) × 96 = 150 pikseli na cal (w przybliżeniu)

  3. Aby uzyskać współczynnik pikseli urządzenia, należy wziąć stosunek fizycznej gęstości pikseli do idealnej gęstości pikseli.

    devicePixelRatio = 180/150 = 1,2

Sposób obliczania devicePixelRatio
Diagram pokazujący jeden referencyjny kątowy piksel, aby zilustrować sposób obliczania współczynnika devicePixelRatio.

Teraz gdy przeglądarka musi wiedzieć, jak zmienić rozmiar obrazu, aby pasował do ekranu w idealnej lub standardowej rozdzielczości, określa współczynnik pikseli urządzenia wynoszący 1,2. Oznacza to, że na każdy idealny piksel urządzenie ma 1,2 piksela fizycznego. Oto formuła do przeliczania pikseli idealnych (zgodnie ze specyfikacją internetową) i fizycznych (punktów na ekranie urządzenia):

physicalPixels = window.devicePixelRatio * idealPixels

W przeszłości dostawcy urządzeń zaokrąglają devicePixelRatios(DPR). iPhone i iPad firmy Apple raportują DPR 1, a ich odpowiedniki Retina – 2. Specyfikacja usługi porównywania cen zaleca, aby

jednostka pikselowa odnosi się do całkowitej liczby pikseli urządzenia, które najlepiej odpowiadają pikselowi referencyjnemu.

Jednym z powodów, dla których proporcje okrągłe mogą być lepsze, jest to, że mogą one powodować mniej artefaktów poniżej piksela.

W rzeczywistości jednak urządzenia są znacznie bardziej zróżnicowane, a DPR telefonów z Androidem wynosi często 1,5. Tablet Nexus 7 ma DPR oraz~1,33, który został obliczony w sposób podobny do opisanego powyżej. W przyszłości spodziewaj się większej liczby urządzeń z rozmaitszymi wartościami DPR. Z tego powodu nigdy nie zakładaj, że klienci będą mieli dokładne DPR.

Omówienie technik tworzenia obrazów HiDPI

Istnieje wiele metod, które pozwalają jak najszybciej rozwiązać problem wyświetlania obrazów o najwyższej jakości. Można je podzielić na 2 kategorie:

  1. optymalizowanie pojedynczych obrazów,
  2. Optymalizowanie wyboru między wieloma obrazami.

Pojedyncze obrazy: użyj jednego obrazu, ale zrób z nim coś sprytnego. Te metody mają tę wadę, że nieuchronnie wiążą się z zawieszeniem wydajności, ponieważ obrazy HiDPI będą pobierane nawet na starszych urządzeniach z niższym DPI. Oto kilka metod na rozwiązanie problemu dotyczącego pojedynczego obrazu:

  • Mocno skompresowany obraz HiDPI
  • Niesamowicie fajny format obrazu
  • Progresywny format obrazu

Podejście z wieloma obrazami: użyj wielu obrazów, ale wybierz sprytny sposób na ich wczytywanie. Takie podejście wiąże się z niezbędnym obciążeniem dla programisty, który musi tworzyć wiele wersji tego samego komponentu, a potem opracowywać strategię podejmowania decyzji. Dostępne opcje to:

  • JavaScript
  • Dostarczanie po stronie serwera
  • Zapytania multimedialne w CSS
  • Wbudowane funkcje przeglądarki (image-set(), <img srcset>)

Mocno skompresowany obraz HiDPI

Obrazy generują już aż 60% przepustowości na pobranie przeciętnej witryny. Podając obrazy w wysokiej rozdzielczości wszystkim klientom, zwiększymy tę liczbę. O ile się powiększy?

Przeprowadziłem kilka testów, w których wyniku wygenerowano fragmenty obrazu w rozdzielczości 1x i 2x z jakością JPEG 90, 50 i 20. Oto skrypt powłoki, którego użyłem do ich wygenerowania (za pomocą ImageMagick):

Kafelki – przykład 1. Przykład kafelków 2. Przykład kafelków 3.
Przykłady obrazów o różnych poziomach kompresji i gęstości pikseli.

Na podstawie tego małego, nienaukowego próbkowania wydaje się, że kompresowanie dużych obrazów zapewnia dobry kompromis między jakością a rozmiarem. Moim zdaniem obrazy skompresowane 2 x wyglądają lepiej niż nieskompresowane obrazy 1 x.

Oczywiście wyświetlanie na urządzeniach 2x obrazów o niskiej jakości, które są mocno skompresowane, jest gorsze niż wyświetlanie obrazów o wyższej jakości, a opisane powyżej podejście powoduje kary za jakość obrazu. Jeśli porównasz jakość (90 obrazów do jakości): 20 obrazów, zauważysz spadek ostrości i większą ziarnistość. Te artefakty mogą być niedopuszczalne w przypadkach, gdy kluczowe znaczenie ma wysoka jakość zdjęć (np. w aplikacji do przeglądania zdjęć) lub w przypadku deweloperów aplikacji, którzy nie chcą iść na kompromis.

Powyższe porównanie zostało wykonane wyłącznie na podstawie skompresowanych plików JPEG. Warto pamiętać, że między powszechnie stosowanymi formatami obrazów (JPEG, PNG, GIF) istnieje wiele kompromisów, co prowadzi nas do…

Znakomity format obrazu

WebP to dość atrakcyjny format obrazów, który bardzo dobrze się skompresuje, zachowując wysoką jakość obrazu. Oczywiście nie jest jeszcze dostępny wszędzie.

Jednym ze sposobów jest sprawdzenie obsługi WebP za pomocą JavaScriptu. Wczytujesz obraz o wymiarach 1 piksela za pomocą identyfikatora URI obiektu, czekasz na wywołanie zdarzeń załadowania lub błędów, a następnie sprawdzasz, czy rozmiar jest prawidłowy. Modernizr zawiera skrypt wykrywania funkcji, który jest dostępny za pomocą Modernizr.webp.

Lepszym sposobem na to jest jednak bezpośrednio w CSS za pomocą funkcji image(). Jeśli masz obraz WebP i JPEG, możesz napisać:

#pic {
  background: image("foo.webp", "foo.jpg");
}

Takie podejście ma kilka wad. Po pierwsze, image() nie jest w ogóle szeroko stosowany. Po drugie, chociaż kompresja WebP powoduje wydmuchnięcie JPEG z wody, nadal jest to stopniowe ulepszenie – około 30% mniej na podstawie tej galerii WebP. Samo rozwiązanie WebP nie wystarczy więc do rozwiązania problemu z wysokim DPI.

Formaty obrazu progresywnego

Formaty obrazów progresywnych, takie jak JPEG 2000, JPEG progresywny, PNG progresywny i GIF, mają (co jest nieco dyskusyjne) tę zaletę, że obraz pojawia się na ekranie przed jego pełnym załadowaniem. Mogą one wiązać się z pewnymi kosztami, ale są na to sprzeczne informacje. Jeff Atwood stwierdził, że tryb progresywny „zwiększa rozmiar obrazów PNG o około 20%, a obrazów JPEG i GIF o około 10%”. Jednak Stojan Stefanov stwierdził, że w przypadku dużych plików tryb progresywny jest wydajniejszy (w większości przypadków).

Na pierwszy rzut oka obrazy progresywne wydają się bardzo obiecujące w kontekście wyświetlania obrazów o najwyższej jakości w jak najkrótszym czasie. Oznacza to, że przeglądarka może przerwać pobieranie i dekodowanie obrazu, gdy tylko stwierdzi, że dodatkowe dane nie poprawią jakości obrazu (czyli wszystkie ulepszenia jakości są poniżej piksela).

Połączenia można łatwo zakończyć, ale ich ponowne uruchomienie często jest drogie. W przypadku witryny z wieloma obrazami najlepszym sposobem jest utrzymanie pojedynczego połączenia HTTP i jak najdłuższe jego ponowne wykorzystanie. Jeśli połączenie zostanie przerwane przedwcześnie, ponieważ obraz został już wystarczająco pobrany, przeglądarka musi utworzyć nowe połączenie, co może być bardzo wolne w środowiskach o niskiej latencji.

Jednym z rozwiązań tego problemu jest użycie żądania HTTP Range, które pozwala przeglądarkom określić zakres bajtów do pobrania. Inteligentna przeglądarka może wysłać żądanie HEAD, aby dotrzeć do nagłówka, przetworzyć je, zdecydować, ile obrazu jest faktycznie potrzebne, a następnie pobrać. Niestety zakres HTTP jest słabo obsługiwany na serwerach WWW, co powoduje, że to podejście jest niepraktyczne.

Oczywistym ograniczeniem tego podejścia jest to, że nie można wybrać obrazu do załadowania, tylko różne poziomy wierności tego samego obrazu. To nie dotyczy przypadku użycia „kierunku artystycznego”.

Używanie JavaScriptu do określania, który obraz ma być wczytany

Pierwszym i najbardziej oczywistym sposobem na określenie, który obraz ma być wczytany, jest użycie JavaScriptu po stronie klienta. Dzięki temu dowiesz się wszystkiego o swoim kliencie użytkownika i możesz podjąć właściwe działania. Możesz określić współczynnik pikseli urządzenia za pomocą funkcji window.devicePixelRatio, poznać szerokość i wysokość ekranu, a nawet wykryć niektóre połączenia sieciowe za pomocą navigator.connection lub wysyłania fałszywego żądania, tak jak robi to biblioteka foresight.js. Gdy już zbierzesz wszystkie te informacje, możesz zdecydować, który obraz ma się wczytać.

Istnieje około miliona bibliotek JavaScript, które wykonują podobne zadania, ale żadna z nich nie wyróżnia się szczególnie.

Jednym z większych minusów tego podejścia jest to, że używanie JavaScriptu oznacza opóźnienie wczytywania obrazu do czasu zakończenia działania parsowania w przyszłości. Oznacza to, że pobieranie obrazów rozpocznie się dopiero po wywołaniu zdarzenia pageload. Więcej informacji na ten temat znajdziesz w artykule Jasona Grigsby'ego.

Zdecyduj, który obraz ma być wczytany na serwerze

Możesz odroczyć decyzję po stronie serwera, tworząc niestandardowe moduły obsługi żądań dla każdego wyświetlanego obrazu. Taki moduł obsługi sprawdza obsługę Retina na podstawie informacji User-Agent (jedynych informacji przekazywanych na serwer). Następnie w zależności od tego, czy logika po stronie serwera chce wyświetlać zasoby HiDPI, musisz wczytać odpowiedni zasób (nazwany zgodnie ze znaną konwencją).

Niestety nagłówek User-Agent nie zawsze zawiera wystarczającą ilość informacji, aby określić, czy urządzenie powinno otrzymać obrazy o wysokiej czy niskiej jakości. Nie trzeba chyba dodawać, że wszystko, co jest związane z User-Agent, jest nielegalne i w miarę możliwości należy tego unikać.

Używanie zapytań mediów w kodzie CSS

Zapytania o media w CSS są deklaratywnymi zapytaniami, które pozwalają określić Twoje intencje i pozwolić przeglądarce na wykonanie odpowiednich działań w Twoim imieniu. Poza najczęstszym zastosowaniem zapytań o multimedia, które dopasowują się do rozmiaru urządzenia, możesz też dopasować devicePixelRatio. Powiązane zapytanie o multimedia to device-pixel-ratio. Jak można się spodziewać, ma ono powiązane warianty minimalny i maksymalny. Jeśli chcesz wczytywać obrazy o wysokiej rozdzielczości, a stosunek pikseli urządzenia przekracza określony próg, możesz wykonać te czynności:

#my-image { background: (low.png); }

@media only screen and (min-device-pixel-ratio: 1.5) {
  #my-image { background: (high.png); }
}

Sprawa komplikuje się, gdy mieszamy ze sobą wszystkie prefiksy dostawców, zwłaszcza ze względu na różnice w umieszczaniu prefiksów „min” i „max”:

@media only screen and (min--moz-device-pixel-ratio: 1.5),
    (-o-min-device-pixel-ratio: 3/2),
    (-webkit-min-device-pixel-ratio: 1.5),
    (min-device-pixel-ratio: 1.5) {

  #my-image {
    background:url(high.png);
  }
}

Dzięki temu podejściu odzyskasz korzyści płynące z analizy wyprzedzającej, które zostały utracone w rozwiązaniu JS. Zyskasz też elastyczność w wybieraniu punktów przerwania w przypadku wersji responsywnych (np. możesz mieć obrazy o niskim, średnim i wysokim DPI), których nie można było wybrać w przypadku podejścia po stronie serwera.

Niestety, jest ona nadal nieco niepraktyczna i prowadzi do dziwnie wyglądającego kodu CSS (lub wymaga wstępnej obróbki). Ponadto to podejście jest ograniczone do właściwości CSS, więc nie ma możliwości ustawienia <img src>, a wszystkie obrazy muszą być elementami z tłem. Jeśli polegasz tylko na współczynniku pikseli urządzenia, może się zdarzyć, że Twój smartfon o wysokiej rozdzielczości pobiera zasób graficzny o rozmiarze 2 x przy połączeniu EDGE. Nie jest to najlepsza opcja dla użytkowników.

Korzystanie z nowych funkcji przeglądarki

Ostatnio dużo dyskutowano na temat obsługi platformy internetowej w kontekście problemu z obrazami o wysokiej rozdzielczości. Apple niedawno wprowadziło na rynek funkcję image-set() do WebKit. W rezultacie zarówno Safari, jak i Chrome obsługują tę funkcję. Ponieważ jest to funkcja CSS, image-set() nie rozwiąże problemu w przypadku tagów <img>. Oto @srcset, który rozwiązuje ten problem, ale (w momencie pisania tego artykułu) nie ma jeszcze implementacji referencyjnych. W następnej sekcji omawiamy szczegółowo image-setsrcset.

Funkcje przeglądarki obsługujące wysoką rozdzielczość DPI

Ostatecznie decyzja o podjętym podejściu zależy od Twoich konkretnych wymagań. Pamiętaj, że wszystkie wymienione powyżej podejścia mają wady. Jednak w przyszłości, gdy image-set i srcset będą powszechnie obsługiwane, będą one odpowiednimi rozwiązaniami tego problemu. Na razie porozmawiajmy o kilku sprawdzonych metodach, które mogą nas zbliżyć do tej idealnej przyszłości.

Po pierwsze, czym różnią się te dwa rodzaje produktów? image-set() to funkcja CSS, którą można wykorzystać jako wartość właściwości CSS tła. srcset to atrybut charakterystyczny dla elementów <img> o podobnej składni. Oba te tagi umożliwiają określenie deklaracji obrazu, ale atrybut srcset pozwala też skonfigurować, który obraz ma być wczytany na podstawie rozmiaru okna przeglądarki.

Sprawdzone metody dotyczące zestawu obrazów

Funkcja CSS image-set() jest dostępna z prefiksem -webkit-image-set(). Składnia jest dość prosta i polega na podaniu co najmniej 1 deklaracji obrazu oddzielonej przecinkami, która składa się z ciągu znaków adresu URL lub funkcji url(), po której następuje powiązana rozdzielczość. Na przykład:

background-image:  -webkit-image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);

Oznacza to, że przeglądarka ma do wyboru 2 obrazy. Jedna z nich jest zoptymalizowana pod kątem wyświetlaczy 1x, a druga – 2x. Przeglądarka wybiera, którą stronę ma wczytać, na podstawie różnych czynników, które mogą obejmować nawet prędkość sieci, jeśli jest wystarczająco inteligentna (o ile mi wiadomo, nie jest to obecnie wdrażane).

Oprócz wczytania prawidłowego obrazu przeglądarka odpowiednio go przeskaluje. Innymi słowy, przeglądarka zakłada, że obrazy w standardowym rozmiarze są dwa razy większe niż w podwójnym, więc zmniejszy obraz w podwójnym rozmiarze 2 razy, aby miał taki sam rozmiar na stronie.

Zamiast podawać 1x, 1,5x lub Nx, możesz też określić konkretną gęstość pikseli urządzenia w dpi.

Takie rozwiązanie działa dobrze, z wyjątkiem przeglądarek, które nie obsługują właściwości image-set, co uniemożliwia wyświetlanie obrazu. To bez wątpienia niekorzystne rozwiązanie, więc do rozwiązania problemu trzeba użyć wartości zastępczej (lub serii wartości zastępczych):

background-image: url(icon1x.jpg);
background-image: -webkit-image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);
/* This will be useful if image-set gets into the platform, unprefixed.
    Also include other prefixed versions of this */
background-image: image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);

W przeglądarkach obsługujących image-set wczytuje się odpowiedni zasób, a w przeciwnym razie wczytuje się zasób 1x. Oczywiste zastrzeżenie jest takie, że chociaż wsparcie przeglądarki image-set() jest niskie, większość agentów użytkownika otrzyma zasób 1x.

W tym pokazie do wczytania prawidłowego obrazu używana jest funkcja image-set(), która w przypadku braku obsługi tej funkcji CSS sięga po zasób 1x.

Zastanawiasz się może, dlaczego nie użyć polyfill (czyli nie tworzyć shimu JavaScriptu) dla image-set()? Okazało się, że wdrożenie wydajnych polyfilli dla funkcji CSS jest dość trudne. (szczegóły znajdziesz w tym dyskusyjnym artykule).

Srcset obrazu

Oto przykład atrybutu srcset:

<img alt="my awesome image"
  src="banner.jpeg"
  srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x">

Jak widać, oprócz deklaracji x, które udostępnia image-set, element srcset przyjmuje też wartości w i h, które odpowiadają rozmiarowi widoku, aby wyświetlić najbardziej odpowiednią wersję. W przypadku powyższych ustawień banner-phone.jpeg będzie wyświetlany na urządzeniach z szerokością widoku mniejszą niż 640 pikseli, banner-phone-HD.jpeg na urządzeniach z małym ekranem i wysoką rozdzielczością, banner-HD.jpeg na urządzeniach z wysoką rozdzielczością i ekranem większym niż 640 pikseli oraz banner.jpeg na wszystkich pozostałych urządzeniach.

Używanie zestawu obrazów dla elementów graficznych

Jako że w większości przeglądarek atrybut srcset nie jest zaimplementowany w elementach img, kuszące może być zastąpienie elementów img elementami <div> z tłem i użycie metody opartej na obrazie. To zadziała, ale z pewnymi zastrzeżeniami. Wadą jest to, że tag <img> ma długą wartość semantyczną. W praktyce jest to ważne głównie ze względów związanych z robotami internetowymi i dostępnością.

Jeśli ostatecznie użyjesz -webkit-image-set, możesz chcieć użyć właściwości CSS background. Wadą tego podejścia jest to, że musisz określić rozmiar obrazu, który jest nieznany, jeśli używasz obrazu o rozmiarze innym niż 1x. Zamiast tego możesz użyć właściwości CSS content w taki sposób:

<div id="my-content-image"
  style="content: -webkit-image-set(
    url(icon1x.jpg) 1x,
    url(icon2x.jpg) 2x);">
</div>

Spowoduje to automatyczne dostosowanie obrazu na podstawie wartości devicePixelRatio. Zobacz ten przykład w praktyce powyższej metody, a dodatkowo w przypadku przeglądarek, które nie obsługują image-set, użyj parametru url().

Polyfilling srcset

Przydatną funkcją srcset jest to, że zawiera naturalne wartości domyślne. Jeśli atrybut srcset nie jest zaimplementowany, wszystkie przeglądarki wiedzą, że należy przetworzyć atrybut src. Jest to po prostu atrybut HTML, więc można utworzyć kod polyfill z JavaScriptem.

Ta funkcja polyfill jest dostarczana z testami jednostkowymi, aby zapewnić jak największe dopasowanie do specyfikacji. Oprócz tego wdrożone są mechanizmy kontroli, które uniemożliwiają polyfillowi wykonanie jakiegokolwiek kodu, jeśli srcset jest implementowany natywnie.

Oto demo funkcji polyfill.

Podsumowanie

Nie ma magicznego sposobu na rozwiązanie problemu obrazów o wysokiej rozdzielczości DPI.

Najłatwiejszym rozwiązaniem jest całkowite unikanie obrazów, wybierając w zamian SVG i CSS. Nie zawsze jest to jednak możliwe, zwłaszcza jeśli masz w witrynie obrazy wysokiej jakości.

Podejścia oparte na JS, CSS i używaniu serwera mają swoje zalety i wady. Najbardziej obiecujące jest jednak korzystanie z nowych funkcji przeglądarki. Chociaż obsługa przeglądarek dla image-set i srcset jest nadal niepełna, obecnie można korzystać z odpowiednich rozwiązań alternatywnych.

Podsumowując, moje zalecenia są następujące: