Тег picture и адаптивные картинки

Знакомство с конструкцией picture, тегом source и адаптацией картинок под размер области просмотра (viewport). Атрибуты srcset, media и sizes тега source, особенности их применения. Примечательно, что весь материал тестировался только в Google Chrome.

picture

HTML-элемент picture (goo.gl/b4IFAC) является контейнером. Он содержит множество source источников для находящегося в нём тега img, используемых браузеров в соответствии с заданными условиями: плотности точек экрана, размера окна, формата изображения и т.д.

Например, мы можем отображать картинку нужного нам размера с учётом размера окна браузера, тем самым, экономя ресурсы пользователя и снижая нагрузку при той же перерисовке картинки.

Примечание: сокращенная запись, с использованием атрибутов srcset и sizes в теге img, не позволила мне добиться описанного выше эффекта. Как я понял, она (на данный момент?) предназначена для задачи множества источников с учётом плотности точек экрана.

HTML-элемент source размещается в контейнере picture. Он содержит информацию об источнике для находящегося в контейнере picture тега img. Можно указать несколько источником для одной картинки, а также условия их использования браузером.

HTML-элемент img размещается в контейнере picture. Он имеет привычный для нас формат и содержит информацию о картинке, которая выводится (условно говоря) «по умолчанию».

Примечание: если браузер не поддерживает конструкцию picture, выводится картинка, заданная в теге img.

Адаптация картинок под размер окна браузера

Для дальнейшего изучения вопроса рассмотрим следующий пример HTML-кода:

<div class="container">
<picture>
<source srcset="image-820.jpg" media="(min-width: 820px)">
<source srcset="image-620.jpg" media="(min-width: 620px)">
<source srcset="image-420.jpg">
<img alt="image" src="image-620.jpg">
</picture>
</div>

Для наглядности я обернул контейнер picture в тег div с классом .container, для которого указал CSS-свойство:

.container { border:4px solid #eee }

Пример работы решения вы можете посмотреть здесь:

В контейнере picture мы имеем тег img (картинка) и несколько тегов source (источник). Если браузер поддерживает конструкцию picture, он будет брать адрес картинки из атрибута srcset тега source, с учётом условий, заданных в атрибуте media. В противном случае будет использоваться адрес картинки из атрибута src тега img.

Построение списка источников идёт от большей картинки к меньшей, т.к. мы используем медиа запрос min-width, обязательно обёрнутый в круглые скобки. Они накладываются один на другой, что позволяет отменить действие предыдущего.

С учётом указанных в примере выше условий, источники для картинки будут использоваться следующим образом:

  • при ширине окна браузера от (не менее) 820 пикселей выводится картинка image-820.jpg;
  • при ширине окна браузера от (не менее) 620 до 820 пикселей выводится картинка image-620.jpg;
  • в остальных случаях, т.е. при ширине окна браузера до 620 пикселей, выводится картинка image-420.jpg.

Визуально это можно отобразить следующим образом:

Последовательность загрузки картинок из источников

Теперь давайте разберёмся с тем, как загружаются картинки из source (источников) и экономятся ресурсы пользователей.

При ширине окна браузера от (не менее) 820 пикселей мы будем иметь следующий результат:

picture source load

Загрузка картинки image-620.jpg была остановлена (canceled) и загрузилась только картинка image-820.jpg.

При ширине окна браузера от (не менее) 620 до 820 пикселей мы будем иметь следующий результат:

picture source load small

По идее, должна была произойти остановка (canceled) загрузки картинки image-420.jpg и загрузиться только картинка image-620.jpg, но произошло только последнее. Причиной тому может быть то, что для картинки image-420.jpg не был указан медиа запрос.

При ширине окна браузера до 620 пикселей, мы получим, схожий, с предыдущим, результат. Загрузится только картинка image-420.jpg и никакой остановки для image-620.jpg.

Примечание: в случае изменения окна браузера (того же поворота мобильного устройства) будут подгружаться дополнительные картинки нужного размера, но только один раз.

Делаем резиновые картинки

Ещё одна особенность констракции picture состоит в том, чтобы «растягивать» картинки под размер окна браузера. Для этого достаточно указать в атрибуте srcset тега source дескриптор ширины картинки.

Для дальнейшего изучения вопроса скорректируем наш пример HTML-кода:

<div class="container">
<picture>
<source srcset="image-820.jpg 820w" media="(min-width: 820px)">
<source srcset="image-620.jpg 620w" media="(min-width: 620px)">
<source srcset="image-420.jpg 420w">
<img alt="image" src="image-620.jpg">
</picture>
</div>

Здесь 820w, 620w и 420w – дескрипторы ширины картинки. Их значения должны соответствовать ширине картинки.

Для наглядности я обернул контейнер picture в тег div с классом .container, для которого указал CSS-свойство:

.container { border:4px solid #eee; width:50% }

Примечание: ширина в 50% была задана для того, чтобы вы смогли увидеть особенность такого «растягивания» картинки.

Пример работы решения вы можете посмотреть здесь:

Чтобы избежать выхода картинки за приделы родительского контейнера (в нашем случае DIV.container), достаточно указать для picture img CSS-свойство: max-width: 100%, например:

picture img { max-width:100% }

Для того же чтобы убрать отступ снизу картинки, лучше всего указать для picture img CSS-свойство: vertical-align: middle, например:

picture img { max-width:100%;vertical-align:middle }

Есть и ещё одна возможность контроля ширины картинки в соответствии с размерами окна браузера – атрибут sizes и новые единицы измерения vw и vh принятые в CSS3.

По сути, они схожи с процентами (%), но ведут отсчет не от родительского контейнера, а от размера окна браузера (viewport).

Подробней о них вы можете прочитать в статье Джонатана Снука (Jonathan Snook) «SIZING WITH CSS3'S VW AND VH UNITS» (goo.gl/hahbY).

Я же приведу лишь пример HTML-кода:

<div class="container">
<picture>
<source srcset="image-820.jpg 820w" media="(min-width: 820px)" sizes="80vw">
<source srcset="image-620.jpg 620w" media="(min-width: 620px)" sizes="60vw">
<source srcset="image-420.jpg 420w">
<img alt="image" src="image-620.jpg">
</picture>
</div>

Пример работы решения вы можете посмотреть здесь:

Примечание: атрибут sizes тега source не будет работать, без указания дескриптора ширины картинки в атрибуте srcset.

На этом у меня всё. Спасибо за внимание. Удачи!

Короткая ссылка: http://goo.gl/0jQdMQ

Сергей Назаров
Сергей Назаров комментирует...

По моему с этой хренью никто особо заморачиваться не будет. До сих пор ни разу не встречал чего-то подобного. Возможно, просто не уделял особого внимания таким деталям. Как по мне решение, что с picture, что с srcset в IMG проработано хреново.

Константин Кирилюк
Константин Кирилюк комментирует...

2Сергей Назаров Согласен, пока это всё далеко от идеала, но и придумать что-то более адекватное не просто. Так что будем пользоваться тем, что есть. Хотя, я и сам пока не особо это всё юзаю. Хотя бы потому, что Google, хоть и умеет обрабатывать picture и srcset, но не использует такое в ранжировании. А ведь до этого было такое разочарование в алгоритме для мобильных … ппц.

globalik slivov
globalik slivov комментирует...

Ну, для практики и наглядности было бы лучше, если бы сами картинки(в примерах) содержали бы вотермарк, типа: "Привет! Я картинка в 600px шириной!" Тогда было бы проще учиться и перехватывать ошибки.