Как предотвратить дублирование загрузки адаптивных изображений.

Элемент <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> элемента. Были загружены два изображения, хотя использовалось только одно из них.

networkpane1-500

Увеличенная версия изображения.

Это происходит, поскольку браузеры «смотрят вперед» и при загрузке 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).

Я сделал пять тестов:

  1. <picture> возвращается к <object>
  2. <picture> возвращается к <embed>
  3. <picture> возвращается к <object>, который возвращается к <embed>
  4. <picture> возвращается к <object>, который возвращается к <img>
  5. <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 Резервное изображение Резерв …

Если вы хотите прочитать полностью статью, посетите сайт наших спонсоров

Comments are closed.