Разработка для Интернета дает вам беспрецедентный охват. Ваше веб-приложение находится на расстоянии одного клика и доступно практически на каждом подключенном устройстве: смартфоне, планшете, ноутбуке и настольном компьютере, телевизоре и т. д., независимо от бренда или платформы. Чтобы обеспечить максимальное удобство, вы создали адаптивный сайт , который адаптирует представление и функциональность для каждого форм-фактора, и теперь вы выполняете контрольный список производительности, чтобы гарантировать, что приложение загружается как можно быстрее: вы оптимизировали критический путь рендеринга , вы сжимали и кэшировали свои текстовые ресурсы, и теперь вы просматриваете свои графические ресурсы, на которые часто приходится большая часть передаваемых байтов. Проблема в том, что оптимизация изображений сложна :
- Определите подходящий формат (векторный или растровый)
- Определить оптимальные форматы кодирования (jpeg, webp и т. д.)
- Определите правильные настройки сжатия (с потерями или без потерь)
- Определите, какие метаданные следует сохранить или удалить.
- Сделайте несколько вариантов каждого для каждого дисплея + разрешение DPR.
- ...
- Учитывайте тип сети, скорость и предпочтения пользователя.
По отдельности это хорошо понятные проблемы . В совокупности они создают большое пространство для оптимизации, которое мы (разработчики) часто упускаем из виду или пренебрегаем. Люди плохо справляются с повторным исследованием одного и того же пространства поиска, особенно когда требуется много шагов. С другой стороны, компьютеры превосходно справляются с задачами такого типа.
Ответ на хорошую и устойчивую стратегию оптимизации изображений и других ресурсов с похожими свойствами прост: автоматизация. Если вы настраиваете свои ресурсы вручную, вы делаете это неправильно: вы забудете, станете ленивы или кто-то другой сделает эту ошибку за вас — гарантировано.
Сага о разработчике, заботящемся о производительности
Поиск в пространстве оптимизации изображений состоит из двух отдельных этапов: времени сборки и времени выполнения.
- Некоторые оптимизации присущи самому ресурсу — например, выбор подходящего формата и типа кодирования, настройка параметров сжатия для каждого кодировщика, удаление ненужных метаданных и т. д. Эти шаги можно выполнить во время сборки.
- Другие оптимизации определяются типом и свойствами клиента, запрашивающего его, и должны выполняться «во время выполнения»: выбор соответствующего ресурса для DPR клиента и предполагаемой ширины дисплея, учет скорости сети клиента, предпочтений пользователя и приложения и т. д.
Инструменты для сборки существуют, но их можно улучшить. Например, можно добиться значительной экономии за счет динамической настройки параметра «качество» для каждого изображения и каждого формата изображения, но я еще не видел, чтобы кто-нибудь действительно использовал это за пределами исследований. Это область, созревшая для инноваций, но для целей данной статьи я оставлю все как есть. Давайте сосредоточимся на оперативной части истории.
<img src="/image/thing" sizes="50vw"
alt="image thing displayed at 50% of viewport width">
Цель приложения очень проста: получить и отобразить изображение на 50% области просмотра пользователя. Именно здесь почти каждый дизайнер моет руки и направляется в бар. Тем временем разработчика, заботящегося о производительности, ждет долгая ночь:
- Чтобы получить наилучшее сжатие, она хочет использовать оптимальный формат изображения для каждого клиента: WebP для Chrome, JPEG XR для Edge и JPEG для остальных.
- Чтобы добиться наилучшего визуального качества, ей необходимо создать несколько вариантов каждого изображения с разным разрешением: 1x, 1,5x, 2x, 2,5x, 3x и, возможно, даже несколько промежуточных.
- Чтобы избежать появления ненужных пикселей, ей необходимо понять, что на самом деле означает «50% области просмотра пользователя» — существует множество различных значений ширины области просмотра!
- В идеале она также хочет обеспечить отказоустойчивость, при которой пользователи в более медленных сетях будут автоматически выбирать более низкое разрешение. В конце концов, пришло время стеклить.
- Приложение также предоставляет некоторые пользовательские элементы управления, которые влияют на то, какой ресурс изображения должен быть получен, так что это тоже следует учитывать.
Да, и тогда дизайнер понимает, что ей нужно отображать другое изображение с шириной 100%, если размер области просмотра мал, чтобы оптимизировать читаемость. Это означает, что теперь нам нужно повторить тот же процесс для еще одного ресурса, а затем сделать выборку зависящей от размера области просмотра. Я уже говорил, что это сложно? Ну ок, давайте к делу. Элемент picture
поможет нам довольно далеко :
<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>
Мы позаботились о художественном оформлении, выборе формата и предоставили шесть вариантов каждого изображения, чтобы учесть различия в DPR и ширине области просмотра устройства клиента. Впечатляющий!
К сожалению, элемент picture
не позволяет нам определять какие-либо правила того, как он должен вести себя в зависимости от типа или скорости соединения клиента. Тем не менее, его алгоритм обработки в некоторых случаях позволяет пользовательскому агенту регулировать, какой ресурс он извлекает — см. шаг 5. Нам просто остается надеяться, что пользовательский агент достаточно умен. (Примечание: ни одна из текущих реализаций не является таковой). Аналогично, в элементе picture
нет перехватчиков, позволяющих использовать логику, специфичную для приложения, которая учитывает предпочтения приложения или пользователя. Чтобы получить эти последние два бита, нам пришлось бы переместить всю вышеописанную логику в JavaScript, но при этом теряется оптимизация сканера предварительной загрузки, предлагаемая picture
. Хм.
Если оставить в стороне эти ограничения, это работает. Ну, по крайней мере, для этого конкретного актива. Реальная и долгосрочная проблема заключается в том, что мы не можем ожидать, что дизайнер или разработчик будет вручную создавать такой код для каждого ресурса. С первой попытки это забавная головоломка, но сразу после этого она теряет свою привлекательность. Нам нужна автоматизация. Возможно, IDE или другие инструменты преобразования контента могут спасти нас и автоматически сгенерировать приведенный выше шаблон.
Автоматизация выбора ресурса с помощью подсказок клиенту
Сделайте глубокий вдох, отбросьте свое неверие и теперь рассмотрите следующий пример:
<meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width">
...
<picture>
<source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing">
<img sizes="100vw" src="/image/thing-crop">
</picture>
Хотите верьте, хотите нет, но приведенного выше примера достаточно, чтобы предоставить все те же возможности, что и гораздо более длинная разметка изображения выше, плюс, как мы увидим, он дает разработчику полный контроль над тем, как, какие и когда извлекаются ресурсы изображения. «Магия» находится в первой строке, которая позволяет сообщать подсказки клиента и сообщает браузеру сообщать серверу о соотношении пикселей устройства ( DPR
), ширине области просмотра макета ( Viewport-Width
) и предполагаемой ширине отображения ( Width
) ресурсов.
Если включены клиентские подсказки, результирующая разметка на стороне клиента сохраняет только требования к представлению . Дизайнеру не нужно беспокоиться о типах изображений, разрешениях клиента, оптимальных точках останова для уменьшения количества доставленных байтов или других критериях выбора ресурсов. Давайте посмотрим правде в глаза: они никогда этого не делали, и им не следовало этого делать. Более того, разработчику также не нужно переписывать и расширять приведенную выше разметку, поскольку фактический выбор ресурсов согласовывается клиентом и сервером.
Chrome 46 обеспечивает встроенную поддержку подсказок DPR
, Width
и Viewport-Width
. По умолчанию подсказки отключены, а приведенный выше <meta http-equiv="Accept-CH" content="...">
служит сигналом согласия, который сообщает Chrome о необходимости добавлять указанные заголовки к исходящим запросам. Имея это в виду, давайте рассмотрим заголовки запроса и ответа для примера запроса изображения:

Chrome объявляет о своей поддержке формата WebP через заголовок запроса Accept ; новый браузер Edge аналогичным образом рекламирует поддержку JPEG XR через заголовок Accept.
Следующие три заголовка запроса — это заголовки client-hint, сообщающие о соотношении пикселей устройства клиента (3x), ширине области просмотра макета (460 пикселей) и предполагаемой ширине отображения ресурса (230 пикселей). Это предоставляет серверу всю необходимую информацию для выбора оптимального варианта изображения на основе его собственного набора политик: наличие предварительно сгенерированных ресурсов, стоимость перекодирования или изменения размера ресурса, популярность ресурса, текущая загрузка сервера и т. д. В этом конкретном случае сервер использует подсказки DPR
и Width
и возвращает ресурс WebP, как указано в заголовках Content-Type
, Content-DPR
и Vary
.
Здесь нет никакой магии. Мы перенесли выбор ресурсов из HTML-разметки в процесс согласования запроса и ответа между клиентом и сервером. В результате HTML касается только требований к представлению, и мы можем доверить его написание любому дизайнеру и разработчику, в то время как поиск в пространстве оптимизации изображений переносится на компьютеры и теперь легко автоматизируется в масштабе. Помните нашего разработчика, заботящегося о производительности? Теперь ее работа — написать сервис изображений, который сможет использовать предоставленные подсказки и возвращать соответствующий ответ: она может использовать любой язык или сервер, который ей нравится, или позволить стороннему сервису или CDN сделать это от ее имени.
<img src="/image/thing" sizes="50vw"
alt="image thing displayed at 50% of viewport width">
Кроме того, помните этого парня выше? Благодаря подсказкам клиента скромный тег изображения теперь учитывает DPR, область просмотра и ширину без какой-либо дополнительной разметки. Если вам нужно добавить художественное оформление, вы можете использовать тег picture
, как мы показали выше, в противном случае все ваши существующие теги изображений станут намного умнее. Клиентские подсказки улучшают существующие элементы img
и picture
.
Получение контроля над выбором ресурсов с помощью сервис-воркера
ServiceWorker, по сути, представляет собой прокси-сервер на стороне клиента, работающий в вашем браузере. Он перехватывает все исходящие запросы и позволяет проверять, перезаписывать, кэшировать и даже синтезировать ответы. Изображения ничем не отличаются, и при включенных клиентских подсказках активный ServiceWorker может идентифицировать запросы изображений, проверять предоставленные клиентские подсказки и определять свою собственную логику обработки.
self.onfetch = function(event) {
var req = event.request.clone();
console.log("SW received request for: " + req.url)
for (var entry of req.headers.entries()) {
console.log("\t" + entry[0] +": " + entry[1])
}
...
}

ServiceWorker предоставляет вам полный контроль над выбором ресурсов на стороне клиента . Это очень важно. Позвольте этому осознаться, потому что возможности почти безграничны:
- Вы можете переписать значения заголовка подсказок клиента, установленные пользовательским агентом.
- Вы можете добавить к запросу новые значения заголовков подсказок клиента.
- Вы можете переписать URL-адрес и указать запрос изображения на альтернативном сервере (например, CDN).
- Вы даже можете переместить значения подсказок из заголовков в сам URL-адрес, если это облегчит развертывание в вашей инфраструктуре.
- Вы можете кэшировать ответы и определять собственную логику, по которой обслуживаются ресурсы.
- Вы можете адаптировать свой ответ в зависимости от возможностей подключения пользователей.
- Вы можете использовать API NetInfo для запроса и объявления своих предпочтений на сервере.
- Вы можете вернуть альтернативный ответ, если выборка выполняется медленно.
- Вы можете учитывать переопределение предпочтений приложений и пользователей.
- Вы можете… делать все, что душе угодно, правда.
Элемент picture
обеспечивает необходимое управление художественным направлением в разметке HTML. Подсказки клиента предоставляют аннотации к результирующим запросам изображений, которые позволяют автоматизировать выбор ресурсов. ServiceWorker предоставляет возможности управления запросами и ответами на клиенте. Это расширяемая сеть в действии.
Клиент подсказки FAQ
Где доступны подсказки для клиентов? Поставляется в Chrome 46 . На рассмотрении в Firefox и Edge .
Почему клиентские подсказки включены? Мы хотим минимизировать накладные расходы для сайтов, которые не будут использовать клиентские подсказки. Чтобы включить подсказки для клиента, сайт должен предоставить заголовок
Accept-CH
или эквивалентную директиву<meta http-equiv>
в разметке страницы. При наличии любого из них пользовательский агент будет добавлять соответствующие подсказки ко всем запросам подресурсов. В будущем мы можем предоставить дополнительный механизм для сохранения этого предпочтения для определенного источника, что позволит доставлять те же подсказки по навигационным запросам.Зачем нам нужны клиентские подсказки, если у нас есть ServiceWorker? ServiceWorker не имеет доступа к информации о макете, ресурсах и ширине области просмотра. По крайней мере, не без введения дорогостоящих двусторонних обходов и значительной задержки запроса изображения - например, когда запрос изображения инициируется анализатором предварительной загрузки. Клиентские подсказки интегрируются с браузером, чтобы сделать эти данные доступными как часть запроса.
Клиентские подсказки предназначены только для ресурсов изображений? Основной вариант использования подсказок DPR, Viewport-Width и Width — включить выбор ресурсов для графических ресурсов. Однако одни и те же подсказки предоставляются для всех подресурсов независимо от типа — например, запросы CSS и JavaScript также получают одну и ту же информацию и также могут использоваться для оптимизации этих ресурсов.
Некоторые запросы изображений не сообщают ширину, почему? Браузер может не знать предполагаемую ширину отображения, поскольку сайт полагается на внутренний размер изображения. В результате подсказка ширины опускается для таких запросов, а также для запросов, которые не имеют «ширины отображения» — например, ресурса JavaScript. Чтобы получать подсказки по ширине, обязательно укажите значение размеров на изображениях.
А как насчет <вставьте мою любимую подсказку> ? ServiceWorker позволяет разработчикам перехватывать и изменять (например, добавлять новые заголовки) все исходящие запросы. Например, легко добавить информацию на основе NetInfo для указания текущего типа соединения — см. « Отчеты о возможностях с помощью ServiceWorker ». «Встроенные» подсказки, поставляемые в Chrome (DPR, Width, Resource-Width), реализованы в браузере, поскольку реализация на основе чистого программного обеспечения будет задерживать все запросы изображений.
Где я могу узнать больше, посмотреть больше демонстраций и что? Ознакомьтесь с поясняющим документом и смело открывайте проблему на GitHub, если у вас есть отзывы или другие вопросы.
Разработка для Интернета дает вам беспрецедентный охват. Ваше веб-приложение находится на расстоянии одного клика и доступно практически на каждом подключенном устройстве: смартфоне, планшете, ноутбуке и настольном компьютере, телевизоре и т. д., независимо от бренда или платформы. Чтобы обеспечить максимальное удобство работы, вы создали адаптивный сайт , который адаптирует представление и функциональность для каждого форм-фактора, и теперь вы выполняете контрольный список производительности, чтобы гарантировать, что приложение загружается как можно быстрее: вы оптимизировали критический путь рендеринга , вы сжимали и кэшировали свои текстовые ресурсы, и теперь вы просматриваете свои графические ресурсы, на которые часто приходится большая часть передаваемых байтов. Проблема в том, что оптимизация изображений сложна :
- Определите подходящий формат (векторный или растровый)
- Определить оптимальные форматы кодирования (jpeg, webp и т. д.)
- Определите правильные настройки сжатия (с потерями или без потерь)
- Определите, какие метаданные следует сохранить или удалить.
- Сделайте несколько вариантов каждого для каждого дисплея + разрешение DPR.
- ...
- Учитывайте тип сети, скорость и предпочтения пользователя.
По отдельности это хорошо понятные проблемы . В совокупности они создают большое пространство для оптимизации, которое мы (разработчики) часто упускаем из виду или пренебрегаем. Люди плохо справляются с повторным исследованием одного и того же пространства поиска, особенно когда требуется много шагов. С другой стороны, компьютеры превосходно справляются с задачами такого типа.
Ответ на хорошую и устойчивую стратегию оптимизации изображений и других ресурсов с похожими свойствами прост: автоматизация. Если вы настраиваете свои ресурсы вручную, вы делаете это неправильно: вы забудете, станете ленивы или кто-то другой сделает эту ошибку за вас — гарантировано.
Сага о разработчике, заботящемся о производительности
Поиск в пространстве оптимизации изображений состоит из двух отдельных этапов: времени сборки и времени выполнения.
- Некоторые оптимизации присущи самому ресурсу — например, выбор подходящего формата и типа кодирования, настройка параметров сжатия для каждого кодировщика, удаление ненужных метаданных и т. д. Эти шаги можно выполнить во время сборки.
- Другие оптимизации определяются типом и свойствами запрашивающего его клиента и должны выполняться «во время выполнения»: выбор соответствующего ресурса для DPR клиента и предполагаемой ширины дисплея, учет скорости сети клиента, предпочтений пользователя и приложения и т. д.
Инструменты для сборки существуют, но их можно улучшить. Например, можно добиться значительной экономии за счет динамической настройки параметра «качество» для каждого изображения и каждого формата изображения, но я еще не видел, чтобы кто-нибудь действительно использовал это за пределами исследований. Это область, созревшая для инноваций, но для целей данной статьи я оставлю все как есть. Давайте сосредоточимся на оперативной части истории.
<img src="/image/thing" sizes="50vw"
alt="image thing displayed at 50% of viewport width">
Цель приложения очень проста: получить и отобразить изображение на 50% области просмотра пользователя. Именно здесь почти каждый дизайнер моет руки и направляется в бар. Тем временем разработчика, заботящегося о производительности, ждет долгая ночь:
- Чтобы получить наилучшее сжатие, она хочет использовать оптимальный формат изображения для каждого клиента: WebP для Chrome, JPEG XR для Edge и JPEG для остальных.
- Чтобы добиться наилучшего визуального качества, ей необходимо создать несколько вариантов каждого изображения с разным разрешением: 1x, 1,5x, 2x, 2,5x, 3x и, возможно, даже несколько промежуточных.
- Чтобы избежать появления ненужных пикселей, ей необходимо понять, что на самом деле означает «50% области просмотра пользователя» — существует множество различных значений ширины области просмотра!
- В идеале она также хочет обеспечить отказоустойчивость, при которой пользователи в более медленных сетях будут автоматически выбирать более низкое разрешение. В конце концов, пришло время стеклить.
- Приложение также предоставляет некоторые пользовательские элементы управления, которые влияют на то, какой ресурс изображения должен быть получен, так что это тоже следует учитывать.
Да, и тогда дизайнер понимает, что ей нужно отображать другое изображение с шириной 100%, если размер области просмотра мал, чтобы оптимизировать читаемость. Это означает, что теперь нам нужно повторить тот же процесс для еще одного ресурса, а затем сделать выборку зависящей от размера области просмотра. Я уже говорил, что это сложно? Ну ок, давайте к делу. Элемент picture
поможет нам довольно далеко :
<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>
Мы позаботились о художественном оформлении, выборе формата и предоставили шесть вариантов каждого изображения, чтобы учесть различия в DPR и ширине области просмотра устройства клиента. Впечатляющий!
К сожалению, элемент picture
не позволяет нам определять какие-либо правила того, как он должен вести себя в зависимости от типа или скорости соединения клиента. Тем не менее, его алгоритм обработки в некоторых случаях позволяет пользовательскому агенту регулировать, какой ресурс он извлекает — см. шаг 5. Нам просто остается надеяться, что пользовательский агент достаточно умен. (Примечание: ни одна из текущих реализаций не является таковой). Аналогично, в элементе picture
нет перехватчиков, позволяющих использовать логику, специфичную для приложения, которая учитывает предпочтения приложения или пользователя. Чтобы получить эти последние два бита, нам пришлось бы переместить всю вышеприведенную логику в JavaScript, но при этом теряется оптимизация сканера предварительной загрузки, предлагаемая picture
. Хм.
Если оставить в стороне эти ограничения, это работает. Ну, по крайней мере, для этого конкретного актива. Реальная и долгосрочная проблема заключается в том, что мы не можем ожидать, что дизайнер или разработчик будет вручную создавать такой код для каждого ресурса. С первой попытки это забавная головоломка, но сразу после этого она теряет свою привлекательность. Нам нужна автоматизация. Возможно, IDE или другие инструменты преобразования контента могут спасти нас и автоматически сгенерировать приведенный выше шаблон.
Автоматизация выбора ресурса с помощью подсказок клиенту
Сделайте глубокий вдох, отбросьте свое неверие и теперь рассмотрите следующий пример:
<meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width">
...
<picture>
<source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing">
<img sizes="100vw" src="/image/thing-crop">
</picture>
Хотите верьте, хотите нет, но приведенного выше примера достаточно, чтобы предоставить все те же возможности, что и гораздо более длинная разметка изображения выше, плюс, как мы увидим, он дает разработчику полный контроль над тем, как, какие и когда извлекаются ресурсы изображения. «Магия» находится в первой строке, которая позволяет сообщать подсказки клиента и сообщает браузеру сообщать серверу о соотношении пикселей устройства ( DPR
), ширине области просмотра макета ( Viewport-Width
) и предполагаемой ширине отображения ( Width
) ресурсов.
Если включены клиентские подсказки, результирующая разметка на стороне клиента сохраняет только требования к представлению . Дизайнеру не нужно беспокоиться о типах изображений, разрешениях клиента, оптимальных точках останова для уменьшения количества доставленных байтов или других критериях выбора ресурсов. Давайте посмотрим правде в глаза: они никогда этого не делали, и им не следовало этого делать. Более того, разработчику также не нужно переписывать и расширять приведенную выше разметку, поскольку фактический выбор ресурса согласовывается клиентом и сервером.
Chrome 46 обеспечивает встроенную поддержку подсказок DPR
, Width
и Viewport-Width
. По умолчанию подсказки отключены, а указанный выше <meta http-equiv="Accept-CH" content="...">
служит сигналом согласия, который сообщает Chrome о необходимости добавлять указанные заголовки к исходящим запросам. Имея это в виду, давайте рассмотрим заголовки запроса и ответа для примера запроса изображения:

Chrome объявляет о своей поддержке формата WebP через заголовок запроса Accept ; новый браузер Edge аналогичным образом рекламирует поддержку JPEG XR через заголовок Accept.
Следующие три заголовка запроса — это заголовки client-hint, сообщающие о соотношении пикселей устройства клиента (3x), ширине области просмотра макета (460 пикселей) и предполагаемой ширине отображения ресурса (230 пикселей). Это предоставляет серверу всю необходимую информацию для выбора оптимального варианта изображения на основе его собственного набора политик: наличие предварительно сгенерированных ресурсов, стоимость перекодирования или изменения размера ресурса, популярность ресурса, текущая загрузка сервера и т. д. В этом конкретном случае сервер использует подсказки DPR
и Width
и возвращает ресурс WebP, как указано в заголовках Content-Type
, Content-DPR
и Vary
.
Здесь нет никакой магии. Мы перенесли выбор ресурсов из HTML-разметки в процесс согласования запроса и ответа между клиентом и сервером. В результате HTML касается только требований к представлению, и мы можем доверить его написание любому дизайнеру и разработчику, в то время как поиск в пространстве оптимизации изображений переносится на компьютеры и теперь легко автоматизируется в масштабе. Помните нашего разработчика, заботящегося о производительности? Теперь ее работа — написать сервис изображений, который сможет использовать предоставленные подсказки и возвращать соответствующий ответ: она может использовать любой язык или сервер, который ей нравится, или позволить стороннему сервису или CDN сделать это от ее имени.
<img src="/image/thing" sizes="50vw"
alt="image thing displayed at 50% of viewport width">
Кроме того, помните этого парня выше? Благодаря подсказкам клиента скромный тег изображения теперь учитывает DPR, область просмотра и ширину без какой-либо дополнительной разметки. Если вам нужно добавить художественное оформление, вы можете использовать тег picture
, как мы показали выше, в противном случае все ваши существующие теги изображений станут намного умнее. Клиентские подсказки улучшают существующие элементы img
и picture
.
Получение контроля над выбором ресурсов с помощью сервис-воркера
ServiceWorker, по сути, представляет собой прокси-сервер на стороне клиента, работающий в вашем браузере. Он перехватывает все исходящие запросы и позволяет проверять, перезаписывать, кэшировать и даже синтезировать ответы. Изображения ничем не отличаются, и при включенных клиентских подсказках активный ServiceWorker может идентифицировать запросы изображений, проверять предоставленные клиентские подсказки и определять свою собственную логику обработки.
self.onfetch = function(event) {
var req = event.request.clone();
console.log("SW received request for: " + req.url)
for (var entry of req.headers.entries()) {
console.log("\t" + entry[0] +": " + entry[1])
}
...
}

ServiceWorker предоставляет вам полный контроль над выбором ресурсов на стороне клиента . Это очень важно. Позвольте этому осознаться, потому что возможности почти безграничны:
- Вы можете переписать значения заголовка подсказок клиента, установленные пользовательским агентом.
- Вы можете добавить к запросу новые значения заголовков подсказок клиента.
- Вы можете переписать URL-адрес и указать запрос изображения на альтернативном сервере (например, CDN).
- Вы даже можете переместить значения подсказок из заголовков в сам URL-адрес, если это облегчит развертывание в вашей инфраструктуре.
- Вы можете кэшировать ответы и определять собственную логику, по которой обслуживаются ресурсы.
- Вы можете адаптировать свой ответ в зависимости от возможностей подключения пользователей.
- Вы можете использовать API NetInfo для запроса и объявления своих предпочтений на сервере.
- Вы можете вернуть альтернативный ответ, если выборка выполняется медленно.
- Вы можете учитывать переопределение предпочтений приложений и пользователей.
- Вы можете… делать все, что душе угодно, правда.
Элемент picture
обеспечивает необходимое управление художественным направлением в разметке HTML. Подсказки клиента предоставляют аннотации к результирующим запросам изображений, которые позволяют автоматизировать выбор ресурсов. ServiceWorker предоставляет возможности управления запросами и ответами на клиенте. Это расширяемая сеть в действии.
Клиент подсказки FAQ
Где доступны подсказки для клиентов? Поставляется в Chrome 46 . На рассмотрении в Firefox и Edge .
Почему клиентские подсказки включены? Мы хотим минимизировать накладные расходы для сайтов, которые не будут использовать клиентские подсказки. Чтобы включить подсказки для клиента, сайт должен предоставить заголовок
Accept-CH
или эквивалентную директиву<meta http-equiv>
в разметке страницы. При наличии любого из них пользовательский агент будет добавлять соответствующие подсказки ко всем запросам подресурсов. В будущем мы можем предоставить дополнительный механизм для сохранения этого предпочтения для определенного источника, что позволит доставлять те же подсказки по навигационным запросам.Зачем нам нужны клиентские подсказки, если у нас есть ServiceWorker? ServiceWorker не имеет доступа к информации о макете, ресурсах и ширине области просмотра. По крайней мере, не без введения дорогостоящих двусторонних обходов и значительной задержки запроса изображения - например, когда запрос изображения инициируется анализатором предварительной загрузки. Клиентские подсказки интегрируются с браузером, чтобы сделать эти данные доступными как часть запроса.
Клиентские подсказки предназначены только для ресурсов изображений? Основной вариант использования подсказок DPR, Viewport-Width и Width — включить выбор ресурсов для графических ресурсов. Однако одни и те же подсказки предоставляются для всех подресурсов независимо от типа — например, запросы CSS и JavaScript также получают одну и ту же информацию и также могут использоваться для оптимизации этих ресурсов.
Некоторые запросы изображений не сообщают ширину, почему? Браузер может не знать предполагаемую ширину отображения, поскольку сайт полагается на внутренний размер изображения. В результате подсказка ширины опускается для таких запросов, а также для запросов, которые не имеют «ширины отображения» — например, ресурса JavaScript. Чтобы получать подсказки по ширине, обязательно укажите значение размеров на изображениях.
А как насчет <вставьте мою любимую подсказку> ? ServiceWorker позволяет разработчикам перехватывать и изменять (например, добавлять новые заголовки) все исходящие запросы. Например, легко добавить информацию на основе NetInfo для указания текущего типа соединения — см. « Отчеты о возможностях с помощью ServiceWorker ». «Встроенные» подсказки, поставляемые в Chrome (DPR, Width, Resource-Width), реализованы в браузере, поскольку реализация на основе чистого программного обеспечения будет задерживать все запросы изображений.
Где я могу узнать больше, посмотреть больше демонстраций и что? Ознакомьтесь с поясняющим документом и смело открывайте проблему на GitHub, если у вас есть отзывы или другие вопросы.
Разработка для Интернета дает вам беспрецедентный охват. Ваше веб-приложение находится на расстоянии одного клика и доступно практически на каждом подключенном устройстве: смартфоне, планшете, ноутбуке и настольном компьютере, телевизоре и т. д., независимо от бренда или платформы. Чтобы обеспечить максимальное удобство работы, вы создали адаптивный сайт , который адаптирует представление и функциональность для каждого форм-фактора, и теперь вы выполняете контрольный список производительности, чтобы гарантировать, что приложение загружается как можно быстрее: вы оптимизировали критический путь рендеринга , вы сжимали и кэшировали свои текстовые ресурсы, и теперь вы просматриваете свои графические ресурсы, на которые часто приходится большая часть передаваемых байтов. Проблема в том, что оптимизация изображений сложна :
- Определите подходящий формат (векторный или растровый)
- Определить оптимальные форматы кодирования (jpeg, webp и т. д.)
- Определите правильные настройки сжатия (с потерями или без потерь)
- Определите, какие метаданные следует сохранить или удалить.
- Сделайте несколько вариантов каждого для каждого дисплея + разрешение DPR.
- ...
- Учитывайте тип сети, скорость и предпочтения пользователя.
По отдельности это хорошо понятные проблемы . В совокупности они создают большое пространство для оптимизации, которое мы (разработчики) часто упускаем из виду или пренебрегаем. Люди плохо справляются с повторным исследованием одного и того же пространства поиска, особенно когда требуется много шагов. С другой стороны, компьютеры превосходно справляются с задачами такого типа.
Ответ на хорошую и устойчивую стратегию оптимизации изображений и других ресурсов с похожими свойствами прост: автоматизация. Если вы настраиваете свои ресурсы вручную, вы делаете это неправильно: вы забудете, станете ленивы или кто-то другой сделает эту ошибку за вас — гарантировано.
Сага о разработчике, заботящемся о производительности
Поиск в пространстве оптимизации изображений состоит из двух отдельных этапов: времени сборки и времени выполнения.
- Некоторые оптимизации присущи самому ресурсу — например, выбор подходящего формата и типа кодирования, настройка параметров сжатия для каждого кодировщика, удаление ненужных метаданных и т. д. Эти шаги можно выполнить во время сборки.
- Другие оптимизации определяются типом и свойствами клиента, запрашивающего его, и должны выполняться «во время выполнения»: выбор соответствующего ресурса для DPR клиента и предполагаемой ширины дисплея, учет скорости сети клиента, предпочтений пользователя и приложения и т. д.
Инструменты для сборки существуют, но их можно улучшить. Например, можно добиться значительной экономии за счет динамической настройки параметра «качество» для каждого изображения и каждого формата изображения, но я еще не видел, чтобы кто-нибудь действительно использовал это за пределами исследований. Это область, созревшая для инноваций, но для целей данной статьи я оставлю все как есть. Давайте сосредоточимся на оперативной части истории.
<img src="/image/thing" sizes="50vw"
alt="image thing displayed at 50% of viewport width">
Цель приложения очень проста: получить и отобразить изображение на 50% области просмотра пользователя. Именно здесь почти каждый дизайнер моет руки и направляется в бар. Тем временем разработчика, заботящегося о производительности, ждет долгая ночь:
- Чтобы получить наилучшее сжатие, она хочет использовать оптимальный формат изображения для каждого клиента: WebP для Chrome, JPEG XR для Edge и JPEG для остальных.
- Чтобы добиться наилучшего визуального качества, ей необходимо создать несколько вариантов каждого изображения с разным разрешением: 1x, 1,5x, 2x, 2,5x, 3x и, возможно, даже несколько промежуточных.
- Чтобы избежать появления ненужных пикселей, ей необходимо понять, что на самом деле означает «50% области просмотра пользователя» — существует множество различных значений ширины области просмотра!
- В идеале она также хочет обеспечить отказоустойчивость, при которой пользователи в более медленных сетях будут автоматически выбирать более низкое разрешение. В конце концов, пришло время стеклить.
- Приложение также предоставляет некоторые пользовательские элементы управления, которые влияют на то, какой ресурс изображения должен быть получен, так что это тоже следует учитывать.
Да, и тогда дизайнер понимает, что ей нужно отображать другое изображение с шириной 100%, если размер области просмотра мал, чтобы оптимизировать читаемость. Это означает, что теперь нам нужно повторить тот же процесс для еще одного ресурса, а затем сделать выборку зависящей от размера области просмотра. Я уже говорил, что это сложно? Ну ок, давайте к делу. Элемент picture
поможет нам довольно далеко :
<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>
Мы позаботились о художественном оформлении, выборе формата и предоставили шесть вариантов каждого изображения, чтобы учесть различия в DPR и ширине области просмотра устройства клиента. Впечатляющий!
К сожалению, элемент picture
не позволяет нам определять какие -либо правила для того, как он должен вести себя на основе типа или скорости подключения клиента. Тем не менее, его алгоритм обработки позволяет пользовательскому агенту регулировать, какой ресурс он извлекает в некоторых случаях - см. Шаг 5. Нам просто нужно надеяться, что пользовательский агент достаточно умный. (Примечание: ни одна из текущих реализаций не является). Точно так же в элементе picture
нет крючков, чтобы разрешить логику для конкретной приложения, которая учитывает приложение или пользовательские предпочтения. Чтобы получить эти последние два бита, нам придется перенести всю вышеперечисленную логику в JavaScript, но это утрачивает оптимизации сканера предварительной нагрузки, предлагаемые picture
. Хм.
Помимо этих ограничений, это работает. Ну, по крайней мере, для этого конкретного актива. Реальная, и долгосрочная задача здесь заключается в том, что мы не можем ожидать, что дизайнер или разработчик будут такими, как это для каждого актива. Это веселая мозговая головоломка с первой попытки, но сразу после этого она теряет свою привлекательность. Нам нужна автоматизация. Возможно, инструменты IDE или другие преобразования контента могут сохранить нас и автоматически генерировать шаблон выше.
Автоматизация выбора ресурсов с помощью клиентских подсказок
Сделайте глубокий вдох, приостановите свое неверие и теперь рассмотрите следующий пример:
<meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width">
...
<picture>
<source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing">
<img sizes="100vw" src="/image/thing-crop">
</picture>
Хотите верьте, хотите нет, но приведен выше пример, чтобы предоставить все те же возможности, что и гораздо более длинная разметка изображения выше, как мы увидим, он позволяет полностью контролировать разработчиков, как, что и когда ресурсы изображения извлекаются. «Магия» находится в первой строке, которая позволяет подсказывать отчеты клиента и говорит браузеру рекламировать соотношение пикселей устройства ( DPR
), ширину просмотра макета ( Viewport-Width
) и предполагаемую ширину отображения ( Width
) ресурсов для сервера.
С включенными клиентскими подсказками, результирующая наставка на стороне клиента сохраняет только требования к презентации . Дизайнер не должен беспокоиться о типах изображений, разрешении клиента, оптимальных точках останова для уменьшения доставленных байтов или других критериев выбора ресурсов. Посмотрим правде в глаза, они никогда не делали, и им не нужно. Лучше, разработчику также не нужно переписать и расширять вышеуказанную разметку, потому что фактический выбор ресурса обсуждается клиентом и сервером.
Chrome 46 обеспечивает собственную поддержку подсказков DPR
, Width
и Viewport-Width
. Подсказки отключены по умолчанию, а <meta http-equiv="Accept-CH" content="...">
выше служит в качестве сигнала, который говорит Chrome, чтобы добавить указанные заголовки к исходящим запросам. При этом давайте рассмотрим заголовки запроса и ответов на пример запроса изображения:

Chrome рекламирует свою поддержку формата Webp через заголовок запроса Accept ; Новый браузер Edge также рекламирует поддержку JPEG XR через заголовок Accept.
Следующими тремя заголовками запросов являются заголовки клиента, рекламирующие соотношение пикселей устройства устройства клиента (3x), ширина просмотра макета (460px) и предполагаемая ширина отображения ресурса (230px). Это предоставляет всю необходимую информацию для сервера для выбора оптимального варианта изображения на основе собственного набора политик: доступность предварительных ресурсов, стоимость повторного кодирования или изменения размера ресурса, популярность ресурса, текущая загрузка сервера и так далее. В этом конкретном случае сервер использует намек на DPR
и Width
и возвращает ресурс WebP, как указано в Content-Type
Content-DPR
и Vary
заголовков.
Здесь нет магии. Мы перенесли выбор ресурса из разметки HTML в переговоры о запросе-ответе между клиентом и сервером. В результате HTML занимается только требованиями презентации, и мы можем доверять любому дизайнеру и разработчику писать, в то время как поиск через пространство оптимизации изображений откладывается на компьютеры и теперь легко автоматизирован в масштабе. Помните нашего разработчика, заботящегося о производительности? Теперь ее работа состоит в том, чтобы написать службу изображений, которая может использовать предоставленные подсказки и возвращать соответствующий ответ: она может использовать любой язык или сервер, который ей нравится, или позволить сторонней службе или CDN сделать это от ее имени.
<img src="/image/thing" sizes="50vw"
alt="image thing displayed at 50% of viewport width">
Кроме того, помните этого парня выше? С клиентами намекает, смиренная тег изображения теперь является DPR-, ViewPort- и шириной без какой-либо дополнительной разметки. Если вам нужно добавить направление искусства, вы можете использовать тег picture
, как мы показали выше, и в противном случае все ваши существующие теги изображения стали намного умнее. Клиентские подсказки улучшают существующие элементы img
и picture
.
Взяв контроль над выбором ресурсов с работником службы
ServiceWorker, по сути, является прокси-сервером на стороне клиента в вашем браузере. Он перехватывает все исходящие запросы и позволяет вам проверять, переписать, кеш и даже синтезировать ответы. Изображения ничем не отличаются, и, поскольку клиентские подсказки включены, активный работник обслуживания может идентифицировать запросы изображения, проверять предоставленные клиентские подсказки и определить свою собственную логику обработки.
self.onfetch = function(event) {
var req = event.request.clone();
console.log("SW received request for: " + req.url)
for (var entry of req.headers.entries()) {
console.log("\t" + entry[0] +": " + entry[1])
}
...
}

ServiceWorker дает вам полный контроль на стороне клиента над выбором ресурса . Это важно. Пусть это погрузится, потому что возможности почти бесконечны:
- Вы можете переписать значения заголовка клиента, установленные пользовательским агентом.
- Вы можете добавить новые клиентские значения заголовков в запрос.
- Вы можете переписать URL и указать запрос изображения на альтернативном сервере (например, CDN).
- Вы даже можете перенести значения подсказки из заголовков в сам URL -адрес, если это облегчает развертывание в вашей инфраструктуре.
- Вы можете кэшировать ответы и определить собственную логику, для которой обслуживаются ресурсы.
- Вы можете адаптировать свой ответ на основе подключения пользователей.
- Вы можете использовать API NetInfo для запроса и рекламы своих предпочтений на сервер.
- Вы можете вернуть альтернативный ответ, если выборка медленная.
- Вы можете учесть переопределение приложений и предпочтений пользователей.
- Вы можете ... сделать все, что ваше сердце желает, правда.
Элемент picture
обеспечивает необходимый контроль над направлением искусства в разметке HTML. Клиентские подсказки предоставляют аннотации по полученным запросам изображения, которые включают автоматизацию выбора ресурсов. ServiceWorker предоставляет возможности для управления запросами и ответов для клиента. Это расширяемая сеть в действии.
Клиент намекает на FAQ
Где доступны клиенты? Поставляется в Chrome 46 . Рассмотря в Firefox и Edge .
Почему клиент намекает на участие? Мы хотим свести к минимуму накладные расходы на сайты, которые не будут использовать клиентские подсказки. Чтобы включить подсказки клиента, сайт должен предоставить заголовок
Accept-CH
или эквивалентный<meta http-equiv>
директива в разметке страницы. С любым из присутствующих, пользовательский агент добавит соответствующие подсказки ко всем запросам Subresource. В будущем мы можем предоставить дополнительный механизм, чтобы сохранить это предпочтение конкретному происхождению, которое позволит поставить те же подсказки по запросам навигации.Зачем нам подсказки клиентов, если у нас есть работник обслуживания? ServiceWorker не имеет доступа к информации о макете, ресурсах и ширине просмотра. По крайней мере, не без введения дорогостоящих обработц и значительно откладывая запрос на изображение - например, когда запрос на изображение инициируется анализатором предварительной нагрузки. Client Hints интегрируется с браузером, чтобы сделать эти данные доступными как часть запроса.
Намекает ли клиент только для ресурсов изображений? Основной вариант использования, лежащий в основе DPR, ширины просмотра и ширины, состоит в том, чтобы включить выбор ресурсов для активов изображений. Тем не менее, одни и те же подсказки доставляются для всех подрушков независимо от типа, например, CSS и запросы JavaScript также получают ту же информацию и могут также использоваться для оптимизации этих ресурсов.
Некоторые запросы на изображение не сообщают о ширине, почему? Браузер может не знать предполагаемую ширину отображения, потому что сайт полагается на внутренний размер изображения. В результате подсказка ширины опущена для таких запросов, и для запросов, которые не имеют «ширины отображения» - например, ресурс JavaScript. Для получения ширины подсказки обязательно укажите значение размеров на ваших изображениях.
А как насчет <вставить мой любимый подсказка> ? ServiceWorker позволяет разработчикам перехватывать и изменять (например, добавить новые заголовки) все исходящие запросы. Например, легко добавить информацию на основе NetInfo , чтобы указать текущий тип подключения -см. « Отчеты о возможностях с обслуживанием ». «Нативные» подсказки, отправленные в Chrome (DPR, ширина, ширина ресурсов), реализованы в браузере, поскольку чистая реализация на основе SW задержит все запросы изображения.
Где я могу узнать больше, увидеть больше демонстраций, а что насчет? Ознакомьтесь с документом по объяснению и не стесняйтесь открыть проблему на GitHub, если у вас есть обратная связь или другие вопросы.