От автора: не нужно быть фанатиком производительности, чтобы знать, что изображения могут сильно замедлить загрузку страниц. Мы проделали долгий путь: от ленивой загрузки изображений и до использования улучшенных форматов типа WebP. Однако все методы включают в себя загрузку одного и того же статичного URL изображения, что может подходить для десктопов, но не для мобильных устройств, и наоборот. У нас появился атрибут srcset в img, но его довольно сложно обслуживать на динамических сайтах, где основной контент делают пользователи.
Я работал с сервисом Cloudinary, который умеет делать буквально все с медиа файлами. Мои предыдущие эксперименты:
оптимизация изображений с помощью Cloudinary;
генерация гистограммы из звука с помощью Cloudinary;
как обеспечить плавное воспроизведение без прерываний (буферизация);
как удалить фон на фотографии с помощью Cloudinary;
лучшие практики по созданию HTML5 видео плееров.
Есть еще один способ оптимизации изображений – клиентские подсказки. Это новый набор HTTP заголовков запроса, которые посылаются на сервер с информацией об устройстве, что позволяет делать более рациональный выбор по выводимому изображению. Точное объяснение, что такое клиентские подсказки из стандартов:
«Данная спецификация определяет набор полей заголовка HTTP запроса или клиентские подсказки. Они используются в качестве входных данных для активного анализа контента. Как и поле заголовка Accept, которое позволяет выбирать форматы, клиентские подсказки позволяют указывать список устройств и определенные настройки браузера.»
Давайте взглянем на то, как сейчас выглядят подсказки к адаптивным изображениям, а также на оптимизацию изображений при помощи клиентских подсказок!
Адаптивные изображения на CSS
На данный момент я создаю адаптивные изображения в CSS двумя способами. Первый – свойство max-width:
1 2 3 |
img { max-width: 100%; } |
Второй способ – захват фоновых изображений с помощью медиа запросов:
1 2 3 4 5 6 7 8 |
.logo { background-image: url('/path/to/tiny-logo.png'); } @media (min-width: 1024px) { .logo { background-image: url('/path/to/large-logo.png'); } } |
У обоих методов есть ряд проблем. Первый метод всегда работает с изображениями большого веса. Второй засоряет CSS и заставляет использовать фоновые изображения.
Адаптивные изображения на JavaScript
В сети много библиотек для адаптивных изображений:
Их гораздо больше, но моя проблема с JS подходом заключается в том, что иногда библиотеки значительно увеличивают вес страницы, а также они не обеспечивают нативный способ изменения изображения. То есть вы сначала ждете загрузку DOM, потом анализируете изображения, далее задаете ширину и посылаете запросы и т.д. Классический подход более производительный.
img srcset
Пока что метод записи нескольких адаптивных изображений немного некрасивый и запутанный:
1 2 3 4 5 6 7 8 9 |
<img sizes="100vw" srcset="tiny.jpg 320w, small.jpg 512w, medium.jpg 640w, large.jpg 1024w, huge.jpg 1280w, enormous.jpg 2048w" src="fallback.jpg" alt="To each according to his ability" /> |
По существу мы задаем новые изображения для определенной ширины экрана в странном формате одной строки. В этом методе вам потребуется создать отдельные изображения или умную систему запросов для динамической генерации изображений. Во многих случаях оба варианта непрактичны.
Работа с клиентскими подсказками
Первый способ – использовать один мета тег, в котором будут записываться подсказки, которые необходимо передать серверу:
1 |
<meta http-equiv="Accept-CH" content="DPR, Width"> |
В коде выше во время запроса изображения мы передаем серверу подсказки по ширине и соотношению пикселей в устройстве. В панели разработчика Chrome во вкладке сеть можно увидеть, что мы послали заголовки:
Если остановиться и подумать, вытянув ширину, соотношение пикселей и другие подсказки из заголовков, мы можем много чего сделать:
мы можем хранить данные, чтобы анализировать шаблоны и, к примеру, обрезать изображения под разные разрешения;
можно генерировать, хранить и возвращать пользовательские изображения по заданному размеру файла;
можно возвращать различные типы изображений под заданное устройство.
Клиентские подсказки – это именно то, чего мы всегда хотели: подсказка от браузера о размере и визуальных характеристиках! Мне очень нравится, что клиентские подсказки довольно легко использовать на стороне клиента. Нужно добавить тег meta, атрибут sizes в изображения и все. Самое сложное начинается на сервере. Необходимо написать динамическую, оптимизированную и адаптивную логику. Тут нам может помочь Cloudinary.
Клиентские подсказки в Cloudinary
Cloudinary хочет сам отвечать за создание и обработку адаптивных изображений. У сервиса есть API для множества языков (Python, Node.js и т.д.), он даже позволяет создавать адаптивные изображения через URL. Давайте создадим изображение с автоматической подсказкой о соотношении пикселей:
1 |
<meta http-equiv="Accept-CH" content="DPR"> <img src="//res.cloudinary.com/demo/w_512,dpr_auto/bike.jpg"> |
Часть адреса w_512,dpr_auto отвечает за отсылку разных изображений пользователям под их условия. В браузерах с поддержкой клиентских подсказок 1х устройства получат 1х изображения, 2х экраны получат 2х изображения. За отсылку разных изображений отвечает плотность отображения.
Теперь при помощи клиентских подсказок давайте создадим изображение с автоматическим подбором ширины:
1 |
<img src="//res.cloudinary.com/demo/w_auto,dpr_auto/bike.jpg"> |
Эффект точно такой же: w_auto посылает изображения разного веса по одному URL на основе клиентской подсказки. Невероятно удобно при создании динамического контента. Не нужно использовать некрасивый атрибут srcset!
Продвинутые клиентские подсказки в Cloudinary
Часть адреса w_auto принимает два необязательных параметра:
1 2 3 4 5 6 7 |
<!-- В <head> --> <meta http-equiv="Accept-CH" content="DPR, Width"> <!-- изображение на странице --> <img sizes="100vw" src="//res.cloudinary.com/demo/w_auto:100:400/bike.jpg" alt="Smiling girl with a bike." /> |
Разберем код выше, особенно часть w_auto:100:400:
100 – инкремент, с помощью которого вычисляется изображение на основе клиентской подсказки. Если задано 1, то изображение будет подогнано под точную ширину макета, что очень плохо. Если у пользователя устройство нестандартной ширины, пострадает производительность. Если клиентская подсказка для ширины width составляет 444, изображение будет округлено до 500 и возвращено.
400 – фолбэк ширина изображения на тот случай, если API клиентских подсказок не поддерживается в браузере, или подсказка просто не была отослана (т.е. в теге не указали Width). Если этот аргумент не указан, вернется полноразмерное изображение. Если изображение очень большое (т.е. оригинал), вам точно понадобится указать данный аргумент.
К сожалению, на данный момент клиентские подсказки поддерживают только Opera и Chrome, а Firefox и Edge только собираются добавить поддержку. Я считаю, по отношению к медиа файлам и экранам устройств это качественный шаг в сторону сближения сервера и клиентской части. Давайте поможем клиентским подсказкам получить глобальное признание. Мы сможем реально улучшить способ получения изображений, особенно если вы используете удивительный сервис Cloudinary!
Автор: David Walsh
Источник: //davidwalsh.name/
Редакция: Команда webformyself.