В прошлом году Джейсон написал серию статей «Адаптивные изображения 101», посвященных новому синтаксису разметки, позволяющему управлять выдачей изображений. В продолжение этой темы необходимо рассказать о Client Hints.

Client Hints – довольно сложная вещь, ее было непросто реализовать. Но она способна значительно упростить дизайнерам ежедневный труд по написанию адаптивного кода.

Что такое Client Hints?

Client Hints – это протокол, при помощи которого браузер в заголовке запроса HTTP может сообщить серверу, какой тип контента он предпочитает получить.

Каждый запрос браузера серверу начинается с HTTP-заголовка. Например, заголовок запроса, который посылает Firefox, чтобы получить нашу домашнюю страницу, выглядит вот так:

GET / HTTP/1.1
 Host: cloudfour.com
 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:47.0) Gecko/20100101 Firefox/47.0
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
 Accept-Language: en-US,en;q=0.5
 Accept-Encoding: gzip, deflate
 Cookie: _ga=GA1.2.333160365.1465672418
 Connection: keep-alive

Заголовки HTTP можно посмотреть с помощью инструментов разработчика любого браузера:

Рис. 1: Заголовки запросов для страницы Cloudfour.com в инструментах разработчика Chrome

Client Hints добавляют дополнительные поля в заголовки HTTP-запросов, содержащие информацию о браузере. Одно из главных применений этой возможности – информирование сервера, какого размера изображения нужны странице.

Client Hints и адаптивные изображения

В Client Hints есть три параметра для запроса соответствующих браузеру изображений:

  • DPR – device pixel ratio, «плотность пикселей», величина аналогичная разрешению
  • Viewport-Width – размеры экрана
  • Width – ширина изображения на странице

Из них наиболее полезны DPR и Width. Как уже рассказывалось в предыдущих статьях, размер viewport малополезен, на узких экранах смартфонов дизайнеры делают изображения почти в ширину экрана, а на десктопах – некоего определенного макетом страницы размера, но в итоге и там и там актуальная ширина изображения оказывается одной и той же.


Ну хорошо, браузер сообщил серверу DDR и Width, сервер их принял и знает, что делать дальше, а вот что делать теперь нам?

Client Hints облегчают разметку

Давайте взглянем на пример кода предыдущих статей «101 серии»:

<img src="cat.jpg" alt="cat"
  srcset="cat-160.jpg 160w,
          cat-320.jpg 320w,
          cat-640.jpg 640w,
          cat-1280.jpg 1280w"
  sizes="(max-width: 480px) 100vw,
         (max-width: 900px) 33vw,
         254px">

Смысл добавления атрибута srcset в разметку – создать для браузера набор изображений различного размера, чтобы он имел возможность запросить то, что ему необходимо. Сервер, в свою очередь, будет знать, какое именно изображение передать браузеру.

Это все обеспечивает свойство Width из Client Hints. Оно вычисляет необходимый размер на основе указанных в sizes размеров и сообщает его в заголовке запроса серверу:

GET cat.jpg
 Accept: image/webp,image/*,*/*;q=0.8
 DPR: 2
 Viewport-Width: 1024
 Width: 508

Теперь же, если и клиент, и сервер поддерживают Clients Hints, разметка может быть сокращена до:

<img src="cat.jpg" alt="cat"
     sizes="(max-width: 480px) 100vw,
       (max-width: 900px) 33vw,
       254px">

Введение этого новшества снимает с дизайнеров и разработчиков всю тяжесть ответственности за выбор границ размеров изображений для тех или иных экранов и перекладывает ее на сервер.

Поддержка множественных форматов изображений

Помимо этого упрощения разметки, еще одно существенное сокращение может быть сделано, если совместить поле Accept-заголовка с возможностями Client Hints.
Это поле используется браузером для того, чтобы сообщить серверу, какие типы данных он считает приемлемыми получить в ответ на данный запрос. Например, когда Chrome запрашивает изображение, он пишет примерно следующее:

Accept: image/webp,image/*,*/*;q=0.8

Здесь написано, что Chrome предпочитает форматы изображений Webp, но если таких нет, то он примет и другие, главное, чтобы их тип начинался с image. Ну, а уж если и такого нет, шлите то, что есть, тут на месте разберемся, говорит Chrome.
Последняя запись «q=0.8» говорит серверу, насколько сильно Chrome предпочитает именно такой формат изображений.
Добавление в заголовок поля Accept позволяет сильно сократить разметку. Вот что было «до того»:

<picture>
  <!-- serve WebP to Chrome and Opera -->
  <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.webp 200w, /image/thing-400.webp 400w,
        /image/thing-800.webp 800w, /image/thing-1200.webp 1200w,
        /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w"
    type="image/webp">
  <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w,
        /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w,
        /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w"
    type="image/webp">
  <!-- serve JPEGXR to Edge -->
  <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpgxr 200w, /image/thing-400.jpgxr 400w,
        /image/thing-800.jpgxr 800w, /image/thing-1200.jpgxr 1200w,
        /image/thing-1600.jpgxr 1600w, /image/thing-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
  <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpgxr 200w, /image/thing-crop-400.jpgxr 400w,
        /image/thing-crop-800.jpgxr 800w, /image/thing-crop-1200.jpgxr 1200w,
        /image/thing-crop-1600.jpgxr 1600w, /image/thing-crop-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
  <!-- serve JPEG to others -->
  <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w,
        /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w,
        /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w">
  <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w,
        /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w,
        /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w">
  <!-- fallback for browsers that don't support picture -->
  <img src="/image/thing.jpg" width="50%">
</picture>

Здесь куча всего: и разные размеры изображений, и разные их форматы, масса источников изображений и т. п. Это, конечно, экстремальный пример. А вот что стало после упрощения с использованием поля Accept:

<picture> 
 <source media="(min-width: 50em)"  
        sizes="50vw"  
        srcset="/image/thing"> 
 <img sizes="100vw" src="/image/thing-crop">
</picture>

Удивительно, правда? Обратите внимание, что пути к изображениям в упрощенной разметке не содержат расширений файлов. Это потому, что Accept говорит серверу, какие типы изображений клиент принимает и какие из них предпочтительны. И это позволяет серверу самому подобрать наилучшее изображение и послать его клиенту.

Забудьте scrset и picture, дайте мне Client Hints!

Некоторые, наверное, удивляются, зачем тратить столько времени на изучение синтаксиса srcset и picture, когда Client Hints делают их практически не нужными.

Не все браузеры поддерживают Client Hints
На сегодня только Chrome и Opera. На стадии рассмотрения – Microsoft Edge и Firefox

Для работоспособности страниц нужен сервер
Иногда HTML используется оффлайн, например, для разметки электронных книг. Но вот разобрать запросы в заголовках и правильно их обработать может только сервер.

Сервер должен поддерживать Client Hints

Сервер должен знать, что делать с запросами Client Hints в заголовках. Мы со временем увидим, как Apache и Nginx добавили Client Hints, но для этого потребуется время, поскольку тут нужно не только разобрать запросы, но нужна еще и система обработки самих изображений.

В краткосрочной перспективе использование Client Hint может заключаться в подключении службы масштабирования изображений, которая будет использовать эту спецификацию. Cloudinary, Imgix и Scientiamobile уже поддерживают Client Hints.

Поддержка Client Hints на сервере – непростая задача

Как и многое другое, связанное с изображениями, реализация Client Hints на сервере сначала кажется легкой. Браузер сообщает серверу размер изображения на странице. Сервер возвращает изображение правильного размера. Всё.

Но начни это делать, и тут же возникают различные проблемы:

Для обеспечения всех возможных клиентов масштабируемыми ресурсами, мы должны обработать и хранить сотни, а то и тысячи копий изображений. Это весьма затратно в смысле вычислительных ресурсов и, кроме того, затрудняет функционирование страниц. Разнообразие ресурсов означает меньшую эффективность использования кэша. Это еще больше замедляет работу, поскольку требуется время на обработку промаха — поиск не найденного в кэше ресурса и его последующее кэширование.

Также, возможно, и не нужны слишком точные настройки, связанные с небольшими изменениями размера экрана или с изменениями его ориентации – может быть, подгрузка чуть большего, чем надо изображения не так уж и вредит, во всяком случае, большее изображение, будучи отмасштабировано браузером, не теряет в качестве.
И нам в самом деле не нужно, хотя и хочется, кэшировать весь массив вариантов изображений в CDN – это будет стоить довольно дорого.

В итоге разные службы обработки изображений могут дать разный результат. Мы дадим им Client Hints – но вот насколько разумно и оптимально они будут обрабатывать эти запросы?

Client Hints нужно подключать опционально

Поскольку разработчикам браузеров не очень интересно посылать лишнюю информацию в каждом запросе, нам нужно явным образом включить Client Hints в теге meta:

<meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width">

Надо просто указать список спецификаций Client Hints, которые мы будем использовать, чтобы избежать лишних записей в заголовках запросов.

Client Hints – и курица и яйцо
Подключение по тегу meta создает головоломку: когда браузер получает страницу, он еще не знает, включен ли Client Hints тегом meta. И сервер не знает, поддерживает ли браузер Client Hints, поскольку пока тег meta не прочитан, браузер даст серверу соответствующие запросы. Это закрывает возможности серверу оптимизировать разметку высылаемого по первому запросу контента и лишает возможности разработчиков оптимизировать код.

Но опциональность – это принципиальный момент, это способ согласовать различные подходы к организации пересылаемого контента вообще. Многие производители браузеров по вполне достойным уважения причинам выступают против какой-либо подгонки, согласования передаваемого контента. А Client Hints – как раз способ такого согласования. Поэтому его нельзя включать по умолчанию.

Как же решить эту головоломку с опциональностью?
Если сервер не знает, поддерживаются ли Client Hints до создания разметки, как мы узнаем, какую именно разметку разрабатывать? Допустим, мы хотим использовать Client Hints. Тут возможны два решения:

  • Определять агента на стороне сервера
  • Поддерживать одновременно два типа разметки: под Client Hints и под адаптивные изображения

Я утверждаю, что если вы используете и разметку для адаптивных изображений и Client Hints, включив его в теге meta, то тогда браузер будет разбирать разметку для адаптивных изображений и запрашивать необходимое в заголовках HTTP.

Так что в краткосрочной перспективе правильнее поддерживать оба вида разметки. Но на самом деле, реально все будет определяться возможностями службы обработки изображений вашего провайдера. Потому сначала проконсультируйтесь у них, что они могут предложить.

Нам все еще нужен синтаксис разметки для работы с адаптивными изображениями

Client Hints – прорывная технология и за ней большое будущее. Когда она будет поддерживаться повсеместно, все, что нам будет нужно из синтаксиса адаптивных изображений – только тэг sizes. Вот почему тэг sizes может стать «супергероем» адаптивных изображений.

Client Hints также говорят нам, что обработка изображений, их классификация по размерам не должна делаться людьми.

По материалам Cloudfour.com

Николай Мациевский

Технический директор облачного сервиса Айри.рф, продукта компании WEBO Group, позволяющего ускорить и защитить любой сайт от наиболее распространенных угроз.
Профессионально занимается скоростью, надежностью и доступностью веб-сайтов уже много лет. Является автором книг «Разгони свой сайт» и «Реактивные веб-сайты». Основатель первой в России компании, профессионально занимающейся повышением качества и быстродействия сайтов различной сложности — WEBO Group. Работает в составе рабочих групп РАЭК, W3C и объединения разработчиков «Веб-стандарты».