Элемент <picture>
– это новое дополнение к HTML5, которое активно поддерживается сообществом по продвижению адаптивных изображений (RICG), созданным W3C (консорциум World Wide Web). Этот элемент предназначен для реализации декларативных решений на основе разметки и позволяет создавать адаптивные изображения без необходимости использования JavaScript библиотек или сложного серверного обнаружения.
Элемент <picture>
поддерживает множество различных типов резервного контента, но текущая реализация системы восстановления имеет определенные проблемы. В этой статье мы рассмотрим, как работает система восстановления, какие у нее есть проблемы и что с помощью неё можно сделать.
Элемент <
picture
>
и резервирование контента.
Также как <video>
и <audio>
, <picture>
использует <source>
элементы для обеспечения возможности выбора браузером из набора изображений. Элементы <source>
необязательно должны содержать type
и media
атрибуты, чтобы указывать браузеру на тип файла и тип источника, соответственно. Анализируя информацию в атрибутах, браузер может визуализировать <source>
с поддерживаемым типом файла и совместимыми информационными запросами. Например:
<picture>
<source src="landscape.webp" type="image/webp" media="screen and (min-width: 20em) and (orientation: landscape)" />
<source src="landscape.jpg" type="image/jpg" media="screen and (min-width: 20em) and (orientation: landscape)" />
<source src="portrait.webp" type="image/webp" media="screen and (max-width: 20em) and (orientation: portrait)" />
<source src="portrait.jpg" type="image/jpg" media="screen and (max-width: 20em) and (orientation: portrait)" />
</picture>
Для ситуаций, в которых браузер не знает, как идентифицировать <picture>
(<video>
или <audio>
) или не может распознать какой-либо из <source>
элементов, разработчик может использовать резервный контент. Резервный контент – это зачастую либо изображение, либо описательный текст; если резервный контент представляет собой <img>
тег, то резервирование обеспечивается в alt
атрибуте (или longdesc
).
<picture>
<source type="image/webp" src="image.webp" />
<source type="image/vnd.ms-photo" src="image.jxr" />
<img src="fallback.jpg" alt="fancy pants">
</picture>
Элемент <picture>
отличается от <video>
и <audio>
тем, что позволяет использовать атрибут srcset
. Атрибут srcset
позволяет разработчику указывать различные изображения на основе пиксельной плотности устройства. При создании адаптивных изображений с использованием и <picture>
, и srcset
, мы получим фрагмент разметки наподобие следующего:
<picture>
<source srcset="big.jpg 1x, big-2x.jpg 2x, big-3x.jpg 3x" type="image/jpeg" media="(min-width: 40em)" />
<source srcset="med.jpg 1x, med-2x.jpg 2x, med-3x.jpg 3x" type="image/jpeg" />
<img src="fallback.jpg" alt="fancy pants" />
</picture>
Основная идея использования элемента <picture>
в примере выше заключается в том, что должно быть загружено ровно одно изображение в зависимости от параметров устройства пользователя:
- Пользователи, чьи устройства поддерживают элемент
<picture>
и имеют ширину окна просмотра, по меньшей мере, 40 em должны получить изображениеbig
. - Пользователи, чьи устройства поддерживают элемент
<picture>
и имеют ширину окна просмотра менее 40 em, должны получить изображениеmed
. - Пользователи, чьи устройства не поддерживают элемент
<picture>
, должны получить резервное изображение.
Если браузер выбирает для отображения big
или med
источник, то он может выбрать изображение с соответствующим разрешением на основе srcset
атрибута:
- Браузер на устройстве с низким разрешением экрана (например, iMac) должен отобразить
1x
изображение. - Браузер на устройств с высоким разрешением (например, iPhone с Retina дисплеем) должен отобразить
2x
изображение. - Браузер на следующее поколение устройств с еще более высоким разрешением должен отобразить
3x
.
Преимуществом для пользователей является то, что всегда загружается только один файл изображения, независимо от поддерживаемых функций, размеров окна или плотности экрана.
Элемент <picture>
также имеет возможность использовать резервирование не связанное с изображениями. Подобный тип резервирования очень удобен из-за своей доступности: если изображение не может быть отображено или если пользователь потребует от вас описания изображения, то в качестве резерва можно использовать <p>
, <span>
, <table>
или любой другой элемент. У вас появляется возможность создать более надежный и соответствующий контенту резерв, чем при простом использовании alt
атрибута.
Проблема резервирования.
На данный момент элемент <picture>
не поддерживается ни в одном из браузеров. Разработчики, которые хотят использовать <picture>
, могут использовать полифилл СкоттаДжела под названием Picturefill. Кроме того, Йоав Вейс создал Chromium ориентированный прототип ссылочного ввода, который имеет частичную поддержку <picture>
. Создание этого Chromium прототипа не только доказывает, что поддержка браузером элемента <picture>
технически возможна, но и дает нам возможность проверить функциональность и ожидаемое поведение.
При тестировании примеров, наподобие тех, что были показаны выше, в своей Chromium сборке, Йоав заметил одну проблему: даже если поддерживается <picture>
элемент, и даже если один из первых двух <source>
элементов был загружен, все равно осуществлялась загрузка резервного <img>
элемента. Были загружены два изображения, хотя использовалось только одно из них.
Увеличенная версия изображения.
Это происходит, поскольку браузеры «смотрят вперед» и при загрузке HTML, сразу же начинается загрузка изображений. Как объясняет сам Йоав:
«Когда парсер встречает img тег, то создается HTMLImageElement узел и к нему добавляются все необходимые атрибуты. Когда добавляются какие-то атрибуты, узел не знает их родительских элементов, а когда добавляется атрибут ‘src’, непосредственно инициируется загрузка изображений».
В большинстве случаев подобная схема прекрасно работает, так как браузер может запускать загрузку изображений еще до того, как завершится загрузка HTML. Но в случаях, когда img
элемент является дочерним <picture>
(или <video>
или <audio>
), браузер не будет (в настоящее время) реагировать на родительский элемент: после того, как будет найден img
элемент, сразу же начнется загрузка. Также возникнет проблема, если мы забудем о родительском элементе и просто рассмотрим <img>
, который имеет как src
, так и srcset
атрибуты: парсер может загрузить src
изображение, прежде чем будет выбран и загружен ресурс из srcset
.
<picture>
<source srcset="big.jpg 1x, big-2x.jpg 2x, big-3x.jpg 3x" media="(min-width: 40em)" />
<source srcset="med.jpg 1x, med-2x.jpg 2x, med-3x.jpg 3x" />
<img src="fallback.jpg" alt="fancy pants" />
<!-- fallback.jpg is *always* downloaded -->
</picture>
<img src="fallback.jpg" srcset="med.jpg 1x, med-2x.jpg 2x, med-3x.jpg 3x" alt="fancy pants" />
<!-- fallback.jpg is *always* downloaded -->
<video>
<source src="video.mp4" type="video/mp4" />
<source src="video.webm" type="video/webm" />
<source src="video.ogv" type="video/ogg" />
<img src="fallback.jpg" alt="fancy pants" />
<!-- fallback.jpg is *always* downloaded -->
</video>
Во всех этих случаях будет происходить загрузка нескольких изображений, а не только того, которое отображается. Но кого это волнует? Ну, хотя бы ваших пользователей, которым приходится загружать дополнительный контент, а также тратить время и деньги, особенно при ограниченной пропускной способности и медленных соединениях. А может быть, эта проблема будет волновать и вас, если приходится платить за трафик.
Потенциальное решение.
Эта проблема требует как краткосрочных, так и долгосрочных решений.
В долгосрочной перспективе, мы должны убедиться, что браузерная реализация элемента <picture>
(<video>
и <audio>
) может преодолеть эту ошибку. Например, Робинn Берён предположил, что содержимое <picture>
можно рассматривать как инертное, также как и содержимое <template>
, а также использовать Shadow DOM (в качестве примера можете посмотреть «Новый шаблонный тег HTML5: стандартизация клиентских шаблонов»). Йоав предложил использовать атрибут <img>
, который должен сообщать браузеру о необходимости загрузить src
.
Изменение схемы работы парсера (анализатора) технически возможно, но реализация будет более сложной. Изменение схемы парсера также может повлиять на JavaScript код и библиотеки, которые предполагают, что загрузка будет инициирована, как только src
атрибут будет добавлен в <img>
. Эти долгосрочные изменения предполагают сотрудничество с производителями браузеров, создателями JavaScript библиотек и разработчиками.
В краткосрочной перспективе мы нуждаемся в работоспособном решении, которое позволяет избежать потери пропускной способности во время экспериментирования с <picture>
и srcset
, а при использовании <video>
и <audio>
с <img>
резервированием. Из-за сложности и ограниченного времени для обновления спецификаций и браузеров, краткосрочное решение должно опираться на существующие инструменты и возможности браузеров.
Так какие же элементы мы можем использовать для поиска возможного решения в настоящее время? Мы можем использовать хорошо знакомые нам элементы <object>
и <embed>
. Оба эти элемента могут быть использованы для отображения изображений. При загрузке изображения с помощью этих тегов, оно будет отображаться правильно в соответствии с условиями резервирования, однако в противном случае загрузка не произойдет.
Различные браузеры ведут себя по-разному в зависимости от того, какой элемент используется: <object>
, <embed>
или оба тега. Чтобы найти лучшее решение, я выполнил тестирование (с помощью слегка модифицированной версии) в:
- Android browser 528.5+/4.0/525.20.1 на Android 1.6 (используя виртуальное устройство Sony Xperia X10 на BrowserStack).
- Android browser 533.1/4.0/533.1 на Android 2.3.3 (используя виртуальное устройство Samsung Galaxy S II на BrowserStack).
- Android browser 534.30/4.0/534.30 на Android 4.2 (используя виртуальное устройство LG Nexus 4 на BrowserStack).
- Chrome 25.0.1364.160 на OS X 10.8.2.
- Chromium 25.0.1336.0 (169465) (RICG сборка) на OS X 10.8.2.
- Firefox 19.0.2 на OS X 10.8.2.
- Internet Explorer 6.0.3790.1830 на Windows XP (используя BrowserStack).
- Internet Explorer 7.0.5730.13 на Windows XP (используя BrowserStack).
- Internet Explorer 8.0.6001.19222 на Windows 7 (используя BrowserStack).
- Internet Explorer 9.0.8112.16421 на Windows 7 (используя BrowserStack).
- Internet Explorer 10.0.9200.16384 (для настольного ПК) на Windows 8 (используя BrowserStack).
- Opera 12.14 сборка 1738 на OS X 10.8.2.
- Opera Mobile 9.80/2.11.355/12.10 на Android 2.3.7 (используя виртуальное устройство Samsung Galaxy Tab 10.1 на Opera Mobile Emulator для Mac).
- Safari 6.0.2 (8536.26.17) на OS X 10.8.2.
- Safari (Mobile) 536.26/6.0/10B144/8536.25 на iOS 6.1 (10B144) (используя iPhone 4).
- Safari (Mobile) 536.26/6.0/10B144/8536.25 на iOS 6.1 (10B141) (используя iPad 2).
Я сделал пять тестов:
<picture>
возвращается к<object>
<picture>
возвращается к<embed>
<picture>
возвращается к<object>
, который возвращается к<embed>
<picture>
возвращается к<object>
, который возвращается к<img>
<picture>
возвращается к<img>
Я обнаружил следующую поддержку:
Испытание1 | Испытание 2 | Испытание 3 | Испытание 4 | Испытание 5 | |
---|---|---|---|---|---|
Android 1.6 | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение |
Android 2.3 | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение |
Android 4.2 | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение |
Chrome 25 | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение |
Chromium 25 (RICG) | Картинка/ источник изображения | Картинка/ источник изображения | Картинка/ источник изображения | Картинка/ источник изображения | Картинка/ источник изображения |
Firefox 19 | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение |
IE 6 | Отсутствие изображения | Отсутствие изображения | Отсутствие изображения | Отсутствие изображения | Резервное изображение |
IE 7 | Отсутствие изображения | Отсутствие изображения | Отсутствие изображения | Отсутствие изображения | Резервное изображение |
IE 8 | Резервное изображение | Отсутствие изображения | Резервное изображение | Резервное изображение | Резервное изображение |
IE 9 | Резервное изображение | Резервные изображения (обрезанное и прокручиваемое) | Резервное изображение | Резервное изображение | Резервное изображение |
IE 10 | Резервное изображение | Резервное изображение (обрезанное и прокручиваемое) | Резервное изображение | Резервное изображение | Резервное изображение |
Opera 12.1 | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение | Резервное изображение |
Opera Mobile 12.1 | Резервное изображение | Резерв … Если вы хотите прочитать полностью статью, посетите сайт наших спонсоров |