HomeSealhub
Responsywne obrazki w HTML

HTML umożliwia nam od pewnego czasu tworzenie responsywnych obrazków. W tym artykule opiszę pokrótce, jak z nich skutecznie korzystać.

Problem

Piksel pikselowi nierówny

Za starych "dobrych" czasów wszystkie ekrany miały zbliżone rozmiary i rozdzielczość. Mieliśmy 640x480, 800x600, 1024x768. Dzięki takiej jednolitości standardem stało się używanie jednostki px do określania rozmiarów elementów stron WWW w CSS.

Gdy rozdzielczości ekranów desktopowych zaczęła rosnąć a na rynku zaczęły pojawiać się urządzenia mobilne o względnie małych ekranach nagle okazało się, że jednostka px jest problematyczna, bo tekst o rozmiarze 20px będzie za duży na smartfonie, a za mały na desktopowym ekranie 4k.

Dlatego przeglądarki przestały traktować jednostkę px dosłownie - teraz ustawiając wysokość jakiegoś elementu na 10px nie mamy gwarancji, że będzie to odpowiadało dokładnie 10-ciu fizycznym pikselom na ekranie. Jeżeli mamy mały ekran o względnie dużej rozdzielczości, to te 10 "pikseli" tak naprawdę może zająć 20 lub nawet 40 faktycznych, fizycznych pikseli.

Przeglądarki na podstawie różnych parametrów określają ilość pikseli fizycznych na jeden piksel css-owy (w Firefoksie można ją skonfigurować pod flagą layout.css.devPixelsPerPx). Im większa ta proporcja, tym większe na naszym ekranie będą elementy wyświetlane przez przeglądarkę.

about:config - Firefox Developer Edition_183.png (715×730 px, 43 KB) about:config - Firefox Developer Edition_184.png (715×730 px, 47 KB)

Dzięki temu użytkownik konfigurując sobie przeglądarkę (lub system operacyjny) może skalibrować ustawienia tak, aby tekst nie był za mały ani za duży.

Ale 1px w css nie zawsze jest równy 1px na ekranie.

O ile tekst można łatwo skalować, o tyle zdjęcia są bardziej problematyczne.

Różne gęstości pikseli

Jeżeli stworzymy sobie grafikę o faktycznym rozmiarze 100px na 100px i osadzimy ją w html:

<img src="100.png" width="100" height="100"/>

To na ekranie o tradycyjnej gęstości pikseli wyświetli się dobrze:

image.png (109×107 px, 2 KB)

ale na ekranie o 2x gęstości jest już gorzej:

scaled.png (110×112 px, 3 KB)

Widzimy, że zdjęcie jest nieostre - jest tak dlatego, że oryginalny plik (o rozdzielczości 100px na 100px) musiał być przez przeglądarkę rozciągnięty do 200x200 fizycznych pikseli, aby je wyświetlić zgodnie z zaprojektowanym layoutem. A skalowanie obrazka zawsze będzie się wiązało z pewną utratą jakości (zwłaszcza, jeżeli rozciągamy zdjęcie, a nie kurczymy).

Jednym z rozwiązań może być wygenerowanie pliku graficznego o rozdzielczości 200x200 i używanie go zamiast pliku 100x100. O ile pomoże to zachować ostrość zdjęć, o tyle spowoduje to kolejny problem - strona staje się "cięższa", bo przeglądarka musi pobrać znacznie więcej danych aby stronę wyświetlić. Do tego dochodzi fakt, że użytkownicy o tradycyjnej rozdzielczości ekranu musieliby wtedy pobierać pliki graficzne o dużej rozdzielczości tylko po to, aby wyświetlać je w mniejszej rozdzielczości - marnując pasmo pobierania na coś, czego nie mogą zobaczyć.

Różne rozmiary ekranu, responsywny layout

Olbrzymie rozdzielczości ekranu nie są jedyną potencjalną przyczyną ładowania zbyt dużych plików graficznych. Responsywne layouty, które dostosowują się do dowolnej szerokości ekranu stwarzają kolejne komplikacje.

Załóżmy, że tworzymy stronę, na której jest widoczne duże zdjęcie - np. post na blogu z coverową grafiką. Tak prezentuje się na desktopie i mobilce:

blog.svg.png (400×533 px, 17 KB) blog-mobile.png (400×533 px, 15 KB)

Jak widać, grafika na mobilce jest znacznie mniejsza, niż na desktopie - i nie jest to w tym wypadku spowodowane zmianą gęstości pikseli, ale różnymi rozmiarami ekranu.

Nie zawsze jest tak, że na mobilkę będziemy wysyłać mniejsze zdjęcia niż na desktop - wszystko zależy od tego, jak ułożymy layout. Na przykład w layoucie opartym o siatkę elementów:

grid-desktop.png (400×533 px, 17 KB) grid-mobile.png (400×533 px, 12 KB)

Grafiki na mobilce są większe, niż na desktopie.

Dołóżmy do tego fakt, że różne telefony i desktopy mogą mieć różną gęstość pikseli i mamy niezłe 🍝, którego zwykłymi media-queries się nie rozplącze.

Rozwiązanie

Na pomoc przychodzą responsywne obrazki.

Dodano do tagu img w HTML dwa nowe atrybuty: srcset i sizes. Możemy ich użyć aby deklaratywnie pomóc przeglądarce samodzielnie wybrać, jaki obrazek będzie najlepszy na danym urządzeniu w danym czasie, biorąc pod uwagę prędkość łącza, rozdzielczość ekranu, wielkość ekranu, gęstość pikseli, etc.

<img
	src="/images/artwork-100w.png"
	srcset="
		/images/artwork-100w.png 100w,
		/images/artwork-200w.png 200w,
		/images/artwork-300w.png 300w,
		/images/artwork-400w.png 400w
	"
	sizes="100px"
/>

W tym przykładzie każdy z wymienionych obrazków (artwork-100w.png, artwork-200w.png itd) są osobnymi plikami umieszczonymi na serwerze i dostępnymi dla przeglądarki. W tym przykładzie możemy założyć, że każdy z tych plików jest tym samym zdjęciem, ale w różnych rozdzielczościach, wygenerowanych na podstawie oryginalnego, znacznie większego pliku graficznego.

W src umieszczamy link do zdjęcia które ma się pojawiać w przeglądarkach które nie wspierają responsywnych obrazków.

W srcset podajemy listę wszystkich plików, spośród których chcemy, aby przeglądarka mogła wybrać ten, który pobierze i wyświetli. Po każdym URL do pliku graficznego podajemy jego szerokość w pikselach. Czyli jeżeli dany link prowadzi do pliku o szerokości 100px, to po jego URL robimy spację i piszemy 100w. w w tym wypadku jest jednostką określającą faktyczny rozmiar zdjęcia w pikselach. Warto zwrócić uwagę, że w powyższym przykładzie plik 100w jest podany w srcset mimo, że znajduje się już w src. Taka duplikacja jest potrzebna, aby ten plik także był brane pod uwagę przez przeglądarkę przy wybieraniu odpowiedniego rozmiaru.

W sizes możemy podać jeden lub więcej (o tym później) rozmiarów grafiki w jednostkach css (podajemy tylko szerokość). Przeglądarka następnie na podstawie rozdzielczości ekranu i gęstości pikseli przekonwertuje te jednostki css do ilości fizycznych pikseli potrzebnych do wyświetlenia grafiki (jednostka w) i wybierze odpowiednie zdjęcie z srcset. Obecność atrybutu sizes jest konieczna, aby uzyskać efekt responsywnych obrazków.

sizes

Po co jest atrybut sizes? Przecież przeglądarka może sobie wywnioskować na podstawie załączonych do html-a css-ów jaki będzie rozmiar zdjęcia na ekranie i to na tej podstawie wybrać odpowiedni plik, prawda?

Otóż nie. Przeglądarka chce pobrać odpowiedni plik graficzny jak najszybciej, a nie dopiero jak załaduje się CSS i zakończy layout całego dokumentu. Dlatego system responsywnych obrazków został zrobiony tak, aby przeglądarka mogła przed wyrenderowaniem layoutu zdecydować, jaki plik zacząć pobierać. Potrzebuje do tego znać tylko rozdzielczość ekranu (lub rozmiar aktualnego okna przeglądarki), gęstość pikseli i informację o tym, jaki rozmiar będzie miało zdjęcie zależnie od rozmiaru ekranu. Dwie pierwsze dane przeglądarka jest w stanie zdobyć samodzielnie - trzecią z nich podajemy jej my, za pomocą atrybutu sizes.

W sizes używamy media conditions (z reguły głównie max-width) aby określić, jaką szerokość będzie miał dany obrazek na danej szerokości.

Pokażę to na przykładzie takiego layoutu, w którym zdjęcie zajmuje całą szerokość ekranu - chyba, że ekran jest bardzo szeroki, to wtedy zdjęcie jest wycentrowane i ma marginesy po bokach:

growing-mobile.png (400×228 px, 10 KB) growing-medium.png (400×450 px, 10 KB) growing-desktop.png (400×758 px, 11 KB)

Przy założeniu, że 900px to ta maksymalna szerokość zdjęcia (podana w css-owych pikselach), to nasz html może wyglądać tak:

<img
  src="artwork-100asdfw.png"
  srcset="
    artwork-100w.png   100w,
    artwork-200w.png   200w,
    artwork-500w.png   500w,
    artwork-1000w.png 1000w,
    artwork-1500w.png 1500w,
    artwork-2000w.png 2000w
  "
  sizes="(max-width: 900px) 100vw,
           900px"
/>

Tutaj w sizes mówimy "Jeżeli ekran ma mniej niż 900 css-owych pikseli, to zdjęcie zajmuje 100% jego szerokości. W przeciwnym wypadku zdjęcie ma 900 css-owych pikseli szerokości". (vw to jednostka css. 100vw= 100% szerokości ekranu. 50vw = 50% szerokości ekranu, itd)

Odpowiednie opisanie sizes może być trochę kłopotliwe, i należy je zaktualizować gdy zmieniamy layout, ale obecnie jest to najlepsze rozwiązanie, pozwalające na optymalizację pasma i dostosowywanie się do różnych rozdzielczości ekranu przy wyświetlaniu obrazków.

Czy robię to dobrze?

Jak już masz ustawione responsywne obrazki na swojej stronie, włącz podgląd zapytań HTTP w narzędziach deweloperskich i zobacz, która wersja zdjęcia jest pobierana. Możesz dodatkowo włączyć tryb responsywny i zmieniać szerokość ekranu i sprawdzić, czy przeglądarka dociąga mniejsze/większe wersje zdjęcia przy odpowiednich zmianach szerokości.

Written by kuba-orlik on Dec 4 2018, 12:49.
CEO
Projects
  • Unknown Object (Project)
Subscribers
None

Event Timeline