Декларативность и сотрудничество в HTML


Есть некоторые клёвые API в HTML/CSS, которые прям доставляют. Чтоб решить задачу, вместо императивщины сообщаешь браузеру нужную инфу, а он делает всю остальную работу.

Хочу рассказать про srcset и sizes у <img>. Для чего они нужны? Прежде всего — подсказать браузеру, какую версию картинки начать загружать, когда только парсится HTML, и браузеру ещё ничего неизвестно о лейауте страницы. Браузер будет полагаться на подсказки, оставленные разработчиком, и исходя из них начинать сразу же загружать нужную картинку, не дожидаясь полного окончания парсинга страницы и применения стилей.

Частый кейс — указание обычной или ретиновой версии картинки. Браузер на этапе загрузки картинки ещё не знает какого она будет размера. Зато при загрузке картинки у браузера уже есть информация, что за экран у устройства: обычный или ретиновый. Поэтому разработчик подсказывает ему: вот эта картинка поменьше — для обычной плотности пикселей (1x), а вот эта картинка побольше — для большей (2x):

<img src="picture1.jpg" srcset="picture1.jpg 1x, picture2.jpg 2x" alt="" />

Браузер получает подсказку от разработчика, какая картинка для какого экрана подходит, и сам делает выбор: если экран ретиновый, грузит 2x-версию, а иначе — 1x. Более сложная логика описания srcset нужна, если разработчик хочет предусмотреть, что на разных разрешениях экрана должны загружаться картинки разного размера. При загрузке картинки у браузера уже есть информация, какой размер вьюпорта на устройстве. А у разработчика есть инфа, какая картинка какому размеру соответствует. То есть разработчик заранее подказывает браузеру: вот эта картинка шириной 100px, вот эта — 500px, а вот эта — 1000px.

<img
src="default.jpg"
srcset="small.jpg 100w, medium.jpg 300w, large.jpg 1000w"
alt=""
/>

Браузер руководствуется подсказкой разработчика и делает выбор: ага, сейчас вьюпорт десктопный >1000px, поэтому беру large.jpg и загружаю. Если бы вьюпорт был поменьше, то была бы загружена соответствующая более мелкая версия картинки. Но картинки не всегда показываются на всю ширину вьюпорта! Ок, браузер выбрал картинку large.jpg, так как вьюпорт был >1000px. А на самом деле картинка после загрузки стилей будет показана не на всю ширину вьюпорта, а вписана в блок шириной 300px. Об этом браузер не мог знать заранее, на этапе, когда он встретил при парсинге разметки тег <img />, и поэтому сделал неверное предположение и загрузил слишком большую картинку. Поэтому браузеру нужна ещё и инфа, которую заранее знает разработчик: какую часть вьюпорта будет занимать картинка, когда страница полностью загрузится. Например, на мобильном разрешении картинка будет на весь экран, а на более широком разрешении три картинки выстроятся в ряд и будут занимать каждая 1/3 размера вьюпорта. Эту инфу и сообщаем браузеру в атрибуте sizes: начиная с 1000px картинка будет занимать треть размера вьюпорта 33.3vw, а в остальных случаях — весь вьюпорт 100vw:

<img sizes="(min-width: 1000px) 33.3vw, 100vw" />

Таким образом у браузера есть все вводные для принятия решения: размер вьюпорта и плотность экрана (браузер знает сам), собственные размеры картинок и их размер на экране (разработчик сообщил в srcset и sizes). И дальше браузер сам принимает решение, какую картинку выбрать. А разработчику не нужно плясать с императивными конструкциями picture, что именно и когда именно браузеру показывать. Вроде всё классно, если разобраться, как это работает. Только вот если не разобраться, то выходит не очень: у sizes по умолчанию значение 100vw. То есть если не указать sizes, а указать только srcset, то браузер будет думать, что картинки всегда на всю ширину вьюпорта, а это часто не так. Выходит так, что фича классная, но если не въехать, как она работает, то толку нет — пользователь будет получать слишком большие картинки там, где мог получить меньшие.