Składnia-przepisy

Element <picture> nie renderuje się samodzielnie, ale działa jak mechanizm decyzyjny dla wewnętrznego elementu <img>, który informuje go, co ma być renderowane. Tag <picture> jest za prefiksem ustawionym przez elementy <audio> i <video> – element otoki, który zawiera poszczególne elementy <source>.

<picture>
   <source …>
   <source …>
    <img …>
</picture …>

Ten wewnętrzny element <img> zapewnia też niezawodny wzorzec zastępczy dla starszych przeglądarek, które nie obsługują obrazów elastycznych: jeśli element <picture> nie zostanie rozpoznany przez przeglądarkę użytkownika, jest ignorowany. Elementy <source> również są odrzucane, ponieważ przeglądarka w ogóle ich nie rozpoznaje lub nie zyskuje dla nich istotnego kontekstu bez elementu nadrzędnego <video> lub <audio>. Wewnętrzny element <img> zostanie jednak rozpoznany przez dowolną przeglądarkę, a źródło określone w elemencie src zostanie wyrenderowane zgodnie z oczekiwaniami.

Obrazy „kierowane na sztukę” zawierające <picture>

Wprowadzanie zmian w zawartości lub współczynniku proporcji obrazu na podstawie jego rozmiaru na stronie jest zwykle nazywane obrazami elastycznymi, które są „skierowane do sztuki”. Źródła srcset i sizes są zaprojektowane tak, aby działały w niezauważalny sposób i płynnie wymieniały źródła w zależności od ustawień przeglądarki użytkownika. Czasami jednak warto zmienić źródła w różnych punktach przerwania, aby lepiej wyróżnić treść, tak samo jak dostosowujesz układy stron. Na przykład: obraz nagłówka o pełnej szerokości z niewielką centralną ostrością może sprawdzić się w dużym widocznym obszarze:

Obraz szerokości nagłówka przedstawiający niebieskofioletowy kwiat otoczony liśćmi i łodygami odwiedzany przez pszczołę.

Jednak po przeskalowaniu w dół, by dopasować go do małych widocznego obszaru, centralny punkt obrazu może zostać utracony:

Obraz przedstawiający niebieskofioletowy kwiat pomniejszony w dół o szerokości nagłówka. Pszczoła jest prawie niewidoczna.

Temat tych źródeł obrazów jest taki sam, ale aby lepiej przedstawić dany temat wizualnie, proporcje źródła obrazu powinny zmieniać się w poszczególnych punktach przerwania. Na przykład silniejsze powiększenie środka obrazu i przycięcie niektórych szczegółów przy krawędziach:

Powiększone przycięcie niebieskofioletowego kwiatu.

Takie „przycinanie” można uzyskać za pomocą CSS, ale powoduje, że użytkownik będzie musiał uzyskać dostęp do wszystkich danych składających się na obraz, nawet jeśli w ogóle go nie zobaczy.

Każdy element source ma atrybuty określające warunki wyboru obiektu source: media, który akceptuje zapytanie o media, i type, który akceptuje typ multimediów (nazywany wcześniej „typem MIME”). Wybrana jest pierwsza pozycja <source> w kolejności źródłowej, która pasuje do bieżącego kontekstu przeglądania użytkownika, a zawartość atrybutu srcset w tym elemencie source zostanie użyta do określenia odpowiednich kandydatów do danego kontekstu. W tym przykładzie wybrany zostanie pierwszy obiekt source z atrybutem media, który pasuje do rozmiaru widocznego obszaru:

<picture>
  <source media="(min-width: 1200px)" srcset="wide-crop.jpg">
  <img src="close-crop.jpg" alt="…">
</picture>

Wewnętrzny element img zawsze należy podawać na końcu. Jeśli żaden z elementów source nie spełnia kryteriów media ani type, obraz będzie źródłem „domyślnym”. Jeśli używasz zapytań o media min-width, chcesz, aby na początku znajdowały się największe źródła, tak jak w poprzednim kodzie. Gdy używasz zapytań o media max-width, umieść na początku najmniejsze źródło.

<picture>
   <source media="(max-width: 400px)" srcset="mid-bp.jpg">
   <source media="(max-width: 800px)" srcset="high-bp.jpg">
   <img src="highest-bp.jpg" alt="…">
</picture>

Gdy źródło zostanie wybrane na podstawie podanych przez Ciebie kryteriów, atrybut srcset w elemencie source jest przekazywany do interfejsu <img> tak, jakby był zdefiniowany w samym pliku <img>. Oznacza to, że możesz używać sizes do optymalizacji źródeł obrazów przeznaczonych dla sztuki.

<picture>
   <source media="(min-width: 800px)" srcset="high-bp-1600.jpg 1600w, high-bp-1000.jpg 1000w">
   <source srcset="lower-bp-1200.jpg 1200w, lower-bp-800.jpg 800w">
   <img src="fallback.jpg" alt="…" sizes="calc(100vw - 2em)">
</picture>

Oczywiście proporcje obrazu, które mogą się różnić w zależności od wybranego elementu <source>, zwiększają wydajność: <img> obsługuje tylko 1 atrybut width i height, ale pominięcie tych atrybutów może znacznie pogorszyć wrażenia użytkownika. Aby to uwzględnić, względnie najnowsze – ale dobrze obsługiwane – dodanie do specyfikacji HTML umożliwia stosowanie atrybutów height i width w elementach <source>. Te działania zmniejszają liczbę przesunięć układu, podobnie jak w <img>, zapewniając w układzie odpowiednie miejsce na wszystkie wybrane elementy <source>.

<picture>
   <source
      media="(min-width: 800px)"
      srcset="high-bp-1600.jpg 1600w, high-bp-1000.jpg 1000w"
      width="1600"
      height="800">
   <img src="fallback.jpg"
      srcset="lower-bp-1200.jpg 1200w, lower-bp-800.jpg 800w"
      sizes="calc(100vw - 2em)"
      width="1200"
      height="750"
      alt="…">
</picture>

Pamiętaj, że kierunku grafiki można używać nie tylko do podejmowania decyzji na podstawie rozmiaru widocznego obszaru, ale ze względu na to, że większość takich przypadków można sprawniej obsługiwać za pomocą metod srcset/sizes. Na przykład wybór źródła obrazu lepiej dopasowanego do schematu kolorów określonych przez użytkownika:

<picture>
   <source media="(prefers-color-scheme: dark)" srcset="hero-dark.jpg">
   <img srcset="hero-light.jpg">
</picture>

Atrybut type

Atrybut type umożliwia korzystanie z mechanizmu podejmowania decyzji o pojedynczym żądaniu w elemencie <picture>, który umożliwia wyświetlanie formatów graficznych tylko w przeglądarkach, które je obsługują.

Jak wiesz z sekcji Formaty obrazów i kompresja, kodowanie, którego nie może przeanalizować przeglądarka, nie jest nawet rozpoznawalne jako dane graficzne.

Przed wprowadzeniem elementu <picture> najskuteczniejsze rozwiązania interfejsu do wyświetlania nowych formatów obrazów wymagały, aby przeglądarka wysyłała żądanie i próbowała przeanalizować plik obrazu, zanim zdecyduje, czy odrzucić go i załadować kreację zastępczą. Typowym przykładem był skrypt o następujących tekstach:

   <img src="image.webp"
    data-fallback="image.jpg"
    onerror="this.src=this.getAttribute('data-fallback'); this.onerror=null;"
    alt="...">

W przypadku tego wzorca żądanie image.webp nadal będzie wysyłane w każdej przeglądarce, co oznacza marne przesyłanie danych w przypadku przeglądarek, które nie obsługują WebP. Przeglądarki, które nie będą mogły następnie przeanalizować kodowania WebP, zgłoszą zdarzenie onerror i zamieni wartość data-fallback na wartość src. Było to stratne rozwiązanie, ale tego typu rozwiązania były jedyną dostępną opcją w interfejsie. Pamiętaj, że przeglądarka zaczyna wysyłać żądania obrazów, zanim niestandardowe skrypty będą mogły zostać uruchomione (lub nawet zostać przeanalizowane), więc nie mogliśmy uprzedzić tego procesu.

Element <picture> został zaprojektowany tak, aby unikać takich zbędnych żądań. Przeglądarka nie może rozpoznać obsługiwanego formatu bez żądania tego, jednak atrybut type od razu ostrzega przeglądarkę o kodowaniu źródłowym, dzięki czemu może ona zdecydować, czy wysłać żądanie.

W atrybucie type podajesz Typ mediów (dawniej typ MIME) źródła obrazu określonego w atrybucie srcset każdego elementu <source>. Dzięki temu przeglądarka otrzyma wszystkie informacje potrzebne do natychmiastowego określenia, czy kandydat do obrazu przesłany przez ten source może zostać zdekodowany bez wysyłania żadnych żądań zewnętrznych. Jeśli typ nośnika nie zostanie rozpoznany, plik <source> i wszystkie jego kandydaci zostaną zignorowane, a przeglądarka przejdzie dalej.

<picture>
 <source type="image/webp" srcset="pic.webp">
 <img src="pic.jpg" alt="...">
</picture>

Tutaj każda przeglądarka, która obsługuje kodowanie WebP, rozpozna typ nośnika image/webp określony w atrybucie type elementu <source>, wybierze go <source>, a ponieważ w srcset jest tylko jedna propozycja, instruuje wewnętrzne <img> żądanie, przeniesienie i wyrenderowanie elementu pic.webp. Każda przeglądarka bez obsługi WebP zignoruje source, a jeśli nie będzie instrukcji, <img> będzie renderować zawartość src w taki sam sposób jak od 1992 roku. Oczywiście nie musisz tu określać drugiego elementu <source> za pomocą atrybutu type="image/jpeg" – możesz założyć, że format JPEG będzie obsługiwany uniwersalnie.

Niezależnie od kontekstu przeglądania przez użytkownika wszystko to jest możliwe przy użyciu pojedynczego przesyłania plików, a konieczność marnowania się na źródła obrazów, których nie można wyrenderować. Ta zmiana wiąże się również z przyszłością: nowsze i bardziej wydajne formaty plików będą zawierać własne typy mediów, a my będziemy mogli korzystać z nich dzięki picture — bez obsługi JavaScriptu, bez zależności po stronie serwera i szybkości <img>.

Przyszłość elastycznych obrazów

Wszystkie omówione tu wzorce znaczników były dużym wyzwaniem w zakresie standaryzacji: zmiana funkcjonalności czegoś, co jest już ustanowione i centralne w internecie, jak <img>, nie była niczym małym, a zestaw problemów, które miały rozwiązać te zmiany, był, delikatnie mówiąc, rozległy. Jeśli uważasz, że te wzorce znaczników można wprowadzić do poprawy, masz absolutną rację. Od samego początku miały one stanowić podstawę dla przyszłych technologii.

Wszystkie te rozwiązania muszą opierać się na znacznikach, więc muszą zostać uwzględnione we wstępnym ładunku z serwera i z czasem, aby przeglądarka wysyłała żądania dotyczące źródeł obrazów. Ograniczenie to spowodowało, że atrybut sizes był zupełnie nieporęczny.

Jednak od momentu wprowadzenia tych funkcji na platformie internetowej wprowadzono natywną metodę odroczenia żądań obrazu. Żądania elementów <img> z atrybutem loading="lazy" są wysyłane dopiero wtedy, gdy znany jest układ strony. Pozwala to opóźnić wysyłanie żądań obrazów poza początkowym widocznym obszarem użytkownika do późniejszego etapu renderowania strony, co pozwala uniknąć niepotrzebnych żądań. Przeglądarka w pełni rozumie układ strony w momencie wysyłania tych żądań, dlatego zaproponowano atrybut sizes="auto" jako uzupełnienie specyfikacji HTML. Pozwoli to uniknąć konieczności ręcznego tworzenia atrybutów sizes w takich przypadkach.

Na horyzoncie widać też dodatki do elementu <picture>, który wprowadza zmiany w sposobie stylizacji układów stron. Informacje o widocznym obszarze są podstawą do podejmowania ogólnych decyzji dotyczących układu, ale uniemożliwiają nam projektowanie na poziomie całego komponentu. Oznacza to, że taki komponent można upuścić w dowolnej części układu strony, a stylowe dostosowują się do przestrzeni zajmowanej przez sam komponent. W rezultacie powstały zapytania dotyczące kontenerów, czyli metoda określania stylu elementów na podstawie rozmiaru ich kontenera nadrzędnego, a nie samego widocznego obszaru.

Mimo że składnia zapytań kontenera dopiero się ustabiliowała, a obsługa przeglądarek jest bardzo ograniczona, dodanie technologii przeglądarek, które je umożliwiają, umożliwiłoby element <picture> zrobienie tego samego: potencjalny atrybut container, który umożliwia stosowanie kryteriów wyboru <source> na podstawie przestrzeni zajmowanej przez element <img> elementu <picture>, a nie na podstawie rozmiaru widocznego obszaru.

Wydaje się to mało niejasne, ale nie bez powodu dyskusja na temat standardów internetowych jest w toku, ale daleko jej do ujednolicenia. Nie można jeszcze jej używać.

Choć używanie elastycznych znaczników obrazów z biegiem czasu, tak jak w przypadku każdej technologii internetowej, wydaje się, że praca z nimi stanie się jeszcze łatwiejsza, istnieje wiele usług, technologii i platform, które ułatwiają pisanie odręczne. W następnym module dowiesz się, jak zintegrować wszystko, czego dowiedzieliśmy się o formatach obrazów, kompresji i elastycznych obrazach, z nowoczesnym procesem programowania.