Тег picture и адаптивные картинки
Знакомство с конструкцией picture, тегом source и адаптацией картинок под размер области просмотра (viewport). Атрибуты srcset
, media
и sizes
тега source, особенности их применения. Примечательно, что весь материал тестировался только в Google Chrome.
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 }
Пример работы решения вы можете посмотреть здесь:
- С кодом: jsfiddle.net/wmas/gozzeobv/
- Результат: jsfiddle.net/wmas/gozzeobv/embedded/result/
В контейнере 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 пикселей мы будем иметь следующий результат:
Загрузка картинки image-620.jpg была остановлена (canceled) и загрузилась только картинка image-820.jpg.
При ширине окна браузера от (не менее) 620 до 820 пикселей мы будем иметь следующий результат:
По идее, должна была произойти остановка (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% была задана для того, чтобы вы смогли увидеть особенность такого «растягивания» картинки.
Пример работы решения вы можете посмотреть здесь:
- С кодом: jsfiddle.net/wmas/pwyx6coq/
- Результат: jsfiddle.net/wmas/pwyx6coq/embedded/result/
Чтобы избежать выхода картинки за приделы родительского контейнера (в нашем случае 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>
Пример работы решения вы можете посмотреть здесь:
- С кодом: jsfiddle.net/wmas/fg99cj3b/1/
- Результат: jsfiddle.net/wmas/fg99cj3b/1/embedded/result/
Примечание: атрибутsizes
тега source не будет работать, без указания дескриптора ширины картинки в атрибутеsrcset
.
На этом у меня всё. Спасибо за внимание. Удачи!
Короткая ссылка: http://goo.gl/0jQdMQ
По моему с этой хренью никто особо заморачиваться не будет. До сих пор ни разу не встречал чего-то подобного. Возможно, просто не уделял особого внимания таким деталям. Как по мне решение, что с picture, что с srcset в IMG проработано хреново.
2Сергей Назаров Согласен, пока это всё далеко от идеала, но и придумать что-то более адекватное не просто. Так что будем пользоваться тем, что есть. Хотя, я и сам пока не особо это всё юзаю. Хотя бы потому, что Google, хоть и умеет обрабатывать picture и srcset, но не использует такое в ранжировании. А ведь до этого было такое разочарование в алгоритме для мобильных … ппц.
Ну, для практики и наглядности было бы лучше, если бы сами картинки(в примерах) содержали бы вотермарк, типа: "Привет! Я картинка в 600px шириной!" Тогда было бы проще учиться и перехватывать ошибки.