Спецификация по отзывчивым изображениям — это фантастический документ, в котором описано множество вариантов использования таких изображений. Но опыт подсказывает мне, что чаще всего при работе с ними нужно знать лишь о том, как отдавать клиенту копии одного и того же изображения разного размера, выбирая их в зависимости от ширины области просмотра страницы. Мы называем это «переключением разрешения». Для решения этой задачи можно воспользоваться атрибутами srcset
и sizes
.
Вывод отзывчивых изображений предусматривает применение достаточно сложной логики. Сюда, кроме прочего, входит определение того, изображение какого размера будет выведено, а также выяснение того, работает ли пользователь с экраном высокого разрешения. К счастью, браузеры лучше, чем люди, умеют определять то, какие именно изображения лучше всего подходят каждому конкретному пользователю. Всё, что нам нужно — это дать им некоторые подсказки. Атрибут srcset
даёт браузеру список графических ресурсов, из которых он может выбирать наиболее подходящее изображение. Атрибут sizes
позволяет сообщить браузеру о том, изображение какого размера нужно показать в том или ином случае.
И, кстати, пользуясь отзывчивыми изображениями можно не беспокоиться о браузерной поддержке этой технологии. Интересующие нас атрибуты пользуются прекрасной поддержкой браузеров. И, кроме того, в нашем распоряжении имеется резервный механизм, предназначенный для старых браузеров вроде IE11.
Как тег «общается» с браузером
Вот как тег <img>
сообщает браузеру о том, какое изображение нужно выбрать.
«Разговор» тега и браузера
Здесь тег <img>
сообщает браузеру следующее: «При таком размере экрана я буду выводиться в примерно следующем размере (указывает на атрибут sizes
). Можешь взять любое из этих изображений, которые имеют следующую ширину (указывает на атрибут srcset
). Поэтому, пожалуйста, выбери то изображение, которое сейчас подходит лучше всего».
Атрибут srcset
Атрибут srcset
даёт браузеру набор графических ресурсов, из которых он может выбирать самый подходящий. Здесь же находятся сведения о размере каждого из предлагаемых изображений.
Атрибут srcset
В атрибуте src
содержится резервный вариант изображения, предназначенный для браузеров, не понимающих атрибута srcset
. В srcset
содержатся URL изображений и сведения об их ширине. Браузер выберет из предоставленного ему набора изображений то, что подходит лучше всего. Причём, если у пользователя имеется дисплей с повышенной плотностью пикселей (Retina-дисплей) — браузер это учтёт при выборе изображения.
Атрибут srcset
содержит список URL изображений, за которыми следуют сведения о ширине изображений. Пары URL-ширина
разделены запятыми. Элементы списка выглядят примерно так: image.jpg 1000w
. Такая запись сообщает браузеру о том, что изображение image.jpg
имеет 1000 пикселей в ширину.
Описывая набор изображений таким способом, мы сообщаем браузеру следующее: «Я даю тебе список изображений и доверяю тебе выбор самого подходящего».
Браузер выберет наилучшее изображение, руководствуясь сложным набором критериев, в которые входит то, изображение какого размера выводится у пользователя, то, каков текущий размер области просмотра, и то, имеется ли у пользователя дисплей высокого разрешения.
Браузер достаточно интеллектуален для того чтобы знать, что на настольном дисплее низкого разрешения, в том случае, если ширина выводимого изображения составляет 800 пикселей, нужно выбрать из списка то изображение, ширина которого составляет, как минимум, 800 пикселей.
Браузер, кроме того, знает о том, что если изображение шириной 320 пикселей выводится на дисплее высокого разрешения, нужно выбрать файл изображения, которое имеет в ширину, как минимум, 640 пикселей. В результате нам не нужно беспокоиться об 1x- и 2x-графических ресурсах. Всё, что нужно сделать — это дать браузеру хороший набор изображений и позволить ему делать своё дело.
Как описывать изображения, подходящие для разных экранов?
Атрибут sizes
Атрибут srcset
— это прекрасный инструмент. Но когда браузер читает HTML-код страницы, он не знает о том, используется ли, например, CSS-стиль, который устанавливает размер изображения в 50% от ширины экрана.
Именно тут в игру вступает атрибут sizes
. С его помощью мы можем дать браузеру подсказку о том, в каком размере будет выводиться изображение после применения к нему CSS.
Атрибут sizes
100vw
— размер, используемый по умолчанию в том случае, когда ни одно из условий не выполняется. Он указывается последним в списке, который имеется в атрибутеsizes
.1023px
— ширина окна.780px
— ширина изображения при выполнении указанного условия.
Браузер остановится на первом выполненном условии.
В атрибуте sizes
содержится список медиа-условий, разделённых запятыми. Медиа-условия — это подмножество медиа-запросов. Тут нельзя указывать тип среды, к которой применимо условие (print
или screen
), но можно использовать медиа-запросы, относящиеся к ширине области просмотра.
Каждая запись списка содержит ширину окна области просмотра и соответствующую ей ширину изображения. Элемент списка имеет вид (min-width: 1023px) 780px
. Подобная запись сообщает браузеру о том, что если ширина области просмотра составляет 1023 пикселя (или больше), то нужно использовать изображение шириной 780 пикселей.
Здесь, кроме того, можно использовать относительные единицы измерения ширины. Например — что-то вроде 50vw
. Это сообщает браузеру о том, что ширина изображения будет составлять 50% ширины области просмотра. Тут, в более сложных ситуациях, можно даже использовать функцию calc
. Например, конструкция вида calc(50vw — 2rem)
сообщает браузеру о том, что ширина изображения будет составлять 50% ширины области просмотра за вычетом 2rem
. Возможно, ширина задана именно так для учёта ширины какого-нибудь отступа или какой-нибудь границы.
Последний элемент списка не снабжён медиа-условием. Если внести в список ширину и не указать медиа-условие, соответствующее значение будет рассматриваться как значение, используемое по умолчанию, то есть — в том случае, если ни одно из других условий не выполняется.
Браузер будет просматривать этот список сверху вниз и остановится на первом подходящем элементе, соответствующем ширине области просмотра.
Предположим, что в атрибуте sizes
находится следующее:
(min-width: 1023px) 780px,
(min-width: 675px) 620px,
100vw
Вот что будет происходить в разных ситуациях:
- Если пользователь работает на большом настольном дисплее, то браузер сочтёт подходящим первый элемент списка и будет знать о том, что ширина изображения должна составлять 780 пикселей.
- Стандартная ширина области просмотра вертикально расположенного экрана iPad составляет 768 пикселей. В такой ситуации браузер пропустит первую запись списка, но обнаружит совпадение текущих условий со второй записью. Она сообщает браузеру о том, что ширина изображения будет составлять 620 пикселей.
- Если пользователь смотрит страницу на типичном мобильном устройстве, то браузер не сочтёт подходящими две первых записи в
sizes
. Поэтому он дойдёт до последней записи, которая скажет ему о том, что ширина изображения будет составлять 100% ширины области просмотра.
Конечно, это — лишь примеры. В реальном мире всё куда сложнее. Например, пользователь с большим экраном, просматривающий страницу в узком окне браузера, получит изображение меньшего размера, чем получил бы, будь окно развёрнуто на весь экран. Пользователь с iPad Pro вполне может получить более крупное изображение в том случае, если расположил устройство в ландшафтном режиме. Если он пользуется планшетом в портретном режиме, ему может достаться изображение среднего размера. А если он пользуется браузером в режиме, когда экран делится между несколькими окнами, то ему может достаться маленькое изображение. Некоторые телефоны с большими экранами будут соответствовать второму правилу из нашего списка при работе с ними в ландшафтном режиме. В этом и состоит прелесть описываемой системы: разработчику не нужно заботиться обо всех этих особых случаях и о разных форм-факторах устройств. Ему достаточно сообщить браузеру о том, какой вариант изображения нужно выбрать для конкретной области просмотра.
Как готовить список изображений, из которых браузер будет выбирать наиболее подходящее?
Атрибут src
Вы могли заметить, что во всех приведённых примерах всё ещё используется атрибут src
. Возможно, вы размышляете о том, нужен ли этот атрибут, учитывая наличие атрибута srcset
. Дело тут в том, что если мы даём браузеру атрибут srcset
, то, если это браузер современный, он заменит значение src
в DOM на значение, соответствующее изображению, выбранному из srcset
. В результате оказывается, что современные браузеры игнорируют атрибут src
, ориентируясь вместо него на атрибут srcset
.
Но атрибут src
, сам по себе, всё ещё важен для браузеров, не поддерживающих работу с отзывчивыми изображениями. Такие браузеры, достаточно старые, игнорируют атрибуты srcset
и sizes
. Они просто не знают об их существовании. Но атрибут src
они понимают, поэтому в него можно записать адрес изображения, которое будет служить резервным вариантом для таких браузеров. Я обычно записывают в этот атрибут адрес самого маленького изображения, которое хорошо смотрится на настольных мониторах, не отличающихся высокой плотностью пикселей.
Вопросы и ответы
▍Как генерировать наборы изображений?
Изображения можно генерировать разными способами: вручную, с использованием инструмента для создания отзывчивых изображений, с применением соответствующих возможностей CDN.
Для того чтобы создать изображения вручную, нужно открыть исходное изображение в Photoshop (или в другом редакторе, которым вы пользуетесь) и экспортировать его во всех необходимых размерах.
Это может потребовать достаточно много времени, поэтому у вас может возникнуть желание автоматизировать эту работу, воспользовавшись соответствующим инструментом. Среди подобных инструментов мне больше всего нравится Responsive Image Breakpoints Generator от Cloudinary. При работе с этим инструментом достаточно передать ему изображение, после чего он автоматически создаст его варианты разных размеров. Тут можно настроить количество генерируемых изображений. После того, как изображения готовы, их можно загрузить и использовать в проекте.
Ещё один вариант поддержки отзывчивых изображений заключается в том, чтобы использовать для их
Вот список сервисов и проектов, которыми можно воспользоваться для создания вариантов изображений разных размеров.
▍Изображения каких размеров следует предоставлять браузеру?
Хороший вопрос! Если вы дадите браузеру слишком много графических ресурсов, то вы попросту впустую потратите время и силы на их создание. Если же ресурсов будет слишком мало — это будет означать, что вы принуждаете пользователей вашего сайта к загрузке изображений, размеры которых больше, чем им нужно.
Если вы работаете с единственным изображением и у вас есть возможность самостоятельно настроить разметку для вывода этого изображения, то можете воспользоваться инструментом Responsive Image Breakpoints Generator. Он автоматически исследует изображение и примет решение о том, каким является оптимальный набор ресурсов (в плане баланса между размерами файлов и их разрешением), сгенерированный на основе этого изображения. Затем этот инструмент не только сгенерирует файлы, но и автоматически подготовит атрибуты srcset
и sizes
.
Стандартный набор размеров изображений шириной от 320 до 2560 пикселей
Если вы работаете в некоей CMS, или если создаёте веб-приложение, и при этом не знаете о том, изображение какого размера будет выведено в том или ином месте, тогда я рекомендую воспользоваться стандартным набором размеров изображений. Раньше я использовал следующие размеры: 320w
, 640w
, 960w
, 1280w
, 1920w
и 2560w
. Это — круглые цифры, получаемые путём умножения 320 на разные коэффициенты. Этот набор ресурсов покрывает нужды самых разных экранов — от маленьких мобильных дисплеев, до огромных настольных мониторов.
Однако использование стандартного набора ресурсов — это всегда менее эффективно, чем применение собственного набора, учитывающего особенности проекта. В данном случае, хотя перед нами — вполне логичная последовательность, в ней наблюдается прогрессивное увеличение размеров файлов, так как, если ширина (и, соответственно, высота) изображения увеличивается вдвое, то количество пикселей этого изображения увеличивается в четыре раза. В результате, если вам приходится использовать стандартный набор размеров изображений, то вам, возможно, следует выбрать такой набор, в котором будет меньше вариантов изображений маленьких размеров и больше вариантов больших размеров.
Если вы хостите изображения на Cloudinary, то вам будет доступен ещё один подход. Он заключается в использовании API Cloudinary, который позволяет обрабатывать изображения с помощью Responsive Image Breakpoints Generator при их загрузке. После того, как изображения автоматически обработаны, можно, воспользовавшись ответом API, динамически заполнить атрибуты srcset
и sizes
.
▍Какие значения следует вносить в атрибут sizes?
Для того чтобы выяснить то, какие значения следует вносить в атрибут sizes
, нужно проанализировать CSS и понять, изображения какой ширины выводятся в различных условиях.
Иногда это определяется шириной самого изображения:
img {
width 320px;
}
@media screen and (min-width: 37.5em) {
width: 640px;
}
В данном случае имеются два фиксированных варианта размера изображения. Этот факт может найти прямое отражение в атрибуте sizes
:
<img
alt="Ferrari"
src="ferrari.jpg"
srcset="ferrari-s.jpg 320w,
ferrari-m.jpg 960w,
ferrari-l.jpg 1920w"
sizes="(min-width: 37.5em) 640px, 320px">
Однако часто оказывается так, что размеры изображений настраиваются гибко. Нередко изображения наследуют размеры от своих контейнеров:
img {
height: auto;
width: 100%;
}
.container {
padding: 1rem;
width: 100%;
}
@media screen and (min-width: 37.5em) {
.container {
width: 50%;
}
}
В этом примере (если исходить из предположения о том, что единственный элемент, воздействующий на ширину изображения, это .container
) ширину контейнера можно счесть шириной изображения. Тут стоит обратить внимание на то, что из ширины контейнера вычитается ширина внутреннего отступа. Возможно, вам понадобится это учитывать, возможно — нет. Всё зависит от того, насколько сильно внутренний отступ влияет на итоговую ширину изображения.
<img
alt="Ferrari"
src="ferrari.jpg"
srcset="ferrari-s.jpg 320w,
ferrari-m.jpg 960w,
ferrari-l.jpg 1920w"
sizes="(min-width: 37.5em) calc(50vw - 2rem),
calc(100vw - 2rem)">
Как видите, настройка атрибута sizes
сильно зависит от особенностей конкретного макета. Обычно я строю работу, начиная с исследования изображений в инструментах разработчика браузера и выясняя то, какие параметры влияют на размер изображений.
▍Как проверить правильность настройки отзывчивых изображений?
Легко представить себе то, что тестирование правильности настройки отзывчивых изображений может быть сложным и длительным делом. Но, к нашему счастью, существует инструмент, упрощающий решение подобных задач. Это — Responsive Image Linter.
Это — букмарклет, который можно добавить в браузер и использовать на собственном сайте. Когда его вызывают, он автоматически сканирует страницу, используя для тестирования изображений различные размеры области просмотра и плотность пикселей экрана.
Затем он выводит отчёт, содержащий сведения обо всех изображениях страницы, и о том, правильно ли организовано управление их размерами. Если при испытании страницы что-то пойдёт не так — вам об этом сообщат и даже дадут совет по устранению проблемы.
Итоги
Как видите, комбинация атрибутов srcset
и sizes
даёт огромные возможности. Настраивая эти два атрибута, вы сообщаете браузеру о ширине изображений, которые нужно использовать при определённой ширине области просмотра, и даёте список графических ресурсов, из которых браузер выбирает тот, который считает наиболее подходящим.
Если при работе с изображениями вам нужно решать более сложные задачи — знайте, что существуют средства и для решения таких задач. Скажем, это нечто вроде использования современных графических форматов наподобие WebP, или отправка клиенту разных изображений, зависящих от размеров экрана. Если вы хотите углубиться в работу с отзывчивыми изображениями — взгляните на этот материал.
Уважаемые читатели! Пользуетесь ли вы отзывчивыми изображениями в своих проектах?
Автор: ru_vds