Разработка сайтов, которые быстро загружаются на любых устройствах, – непростая задача. Множество возможностей устройств и качество сетей, к которым они подключаются, могут сделать эту задачу невыполнимой. Хотя мы можем использовать функции браузера для повышения производительности загрузки, как мы узнаем, на что способно устройство пользователя или каково качество его сетевого подключения? Решение – подсказки клиента.
Подсказки клиента – это набор заголовков HTTP-запросов, которые позволяют нам получать информацию об устройстве пользователя и сети, к которой оно подключено. Используя эту информацию на стороне сервера, мы можем изменить способ доставки контента в зависимости от устройства и/или условий сети. Это может помочь нам создать более инклюзивный пользовательский опыт.
Все дело в согласовании контента
Подсказки клиента – это ещё один метод согласования контента, то есть изменения ответов на основе заголовков запросов браузера.
Один из примеров согласования контента – заголовок запроса Accept. Он описывает, какие типы контента понимает браузер, что сервер может использовать для согласования ответа. Для запросов изображений заголовок Accept в Chrome выглядит следующим образом:
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Хотя все браузеры поддерживают такие графические форматы, как JPEG, PNG и GIF, заголовок Accept в этом случае сообщает, что браузер также поддерживает WebP и APNG. Используя эту информацию, мы можем согласовать лучшие типы изображений для каждого браузера:
<?php
// Check Accept for an "image/webp" substring.
$webp = stristr($_SERVER["HTTP_ACCEPT"], "image/webp") !== false ? true : false;
// Set the image URL based on the browser's WebP support status.
$imageFile = $webp ? "whats-up.webp" : "whats-up.jpg";
?>
<img src="<?php echo($imageFile); ?>" alt="I'm an image!">
Как и Accept, подсказки клиента – это ещё один способ согласования контента, но в контексте возможностей устройства и условий сети. С помощью подсказок клиента мы можем принимать решения о производительности на стороне сервера на основе индивидуального опыта пользователя, например, решать, следует ли предоставлять некритические ресурсы пользователям с плохими условиями сети. В этом руководстве мы опишем все доступные подсказки и способы их использования, чтобы сделать распространение контента более удобным для пользователей.
Включение
В отличие от заголовка Accept, подсказки клиента не появляются сами по себе (за исключением Save-Data, о котором мы поговорим позже). Чтобы не перегружать заголовки запросов, вам нужно выбрать, какие подсказки клиента вы хотите получать, отправив заголовок Accept-CH, когда пользователь запрашивает ресурс:
Accept-CH: Viewport-Width, Downlink
Значение Accept-CH – это список запрашиваемых подсказок, разделенных запятыми, которые сайт будет использовать для определения результатов последующего запроса ресурса. Когда клиент считывает этот заголовок, он получает сообщение "этому сайту нужны подсказки клиента Viewport-Width и Downlink". Не беспокойтесь о самих подсказках.
Мы скоро к ним вернемся.
Заголовки согласия можно задавать на любом языке серверной части. Например, можно использовать функцию header в PHP.
Вы даже можете задать эти заголовки с помощью атрибута http-equiv в теге <meta>:
<meta http-equiv="Accept-CH" content="Viewport-Width, Downlink" />
Все клиентские подсказки
Клиентские подсказки описывают одно из двух: устройство, которое используют ваши пользователи, и сеть, которую они используют для доступа к вашему сайту. Давайте кратко рассмотрим все доступные подсказки.
Советы по устройствам
Некоторые подсказки клиента описывают характеристики устройства пользователя, обычно характеристики экрана. Некоторые из них помогают выбрать оптимальный медиаресурс для экрана пользователя, но не все они ориентированы на медиа.
Прежде чем мы перейдем к списку, может быть полезно узнать несколько ключевых терминов, используемых для описания экранов и разрешения медиа:
Встроенный размер – фактические размеры медиаресурса. Например, если вы откроете изображение в Photoshop, размеры, показанные в диалоговом окне размера изображения, описывают его внутренний размер.
Внутренний размер с поправкой на плотность. Размеры медиаресурса после корректировки плотности пикселей. Это внутренний размер изображения, разделенный на соотношение логических и физических пикселей устройства. Рассмотрим следующий пример разметки:
<img
src="whats-up-1x.png"
srcset="whats-up-2x.png 2x, whats-up-1x.png 1x"
alt="I'm that image you wanted."
/>
Допустим, что внутренний размер изображения 1x в этом случае составляет 320 x 240, а изображения 2x – 640 x 480. Если эта разметка обрабатывается клиентом, установленным на устройстве с коэффициентом соотношения пикселей экрана, равным 2 (например, с экраном Retina), запрашивается изображение 2x. Внутренний размер с поправкой на плотность для изображения 2x составляет 320 x 240, поскольку 640 x 480, деленное на 2, равно 320 x 240.
Внешний размер – размер медиаресурса после применения к нему CSS и других факторов макета (например, атрибутов width и height). Допустим, у вас есть элемент <img>, который загружает изображение с внутренним размером 320 x 240, скорректированным с учетом плотности, но к нему также применены свойства CSS width и height со значениями 256px и 192px соответственно. В этом примере внешний размер элемента <img> становится равным 256 x 192.
width: 256px; и height: 192px; преобразует изображение с внутренним размером 320 x 240 в изображение с внешним размером 256 x 192.Теперь, когда мы разобрались с терминологией, давайте перейдем к списку подсказок клиента, относящихся к конкретному устройству.
Viewport-Width
Viewport-Width – ширина области просмотра в пикселях CSS:
Viewport-Width: 320
Эту подсказку можно использовать вместе с другими подсказками, относящимися к экрану, чтобы показывать разные версии (например, кадрированные) изображения, которые оптимальны для экранов определенных размеров (художественное оформление), или пропускать ресурсы, которые не нужны для текущей ширины экрана.
DPR
DPR – это соотношение физических пикселей и пикселей CSS на экране пользователя.
DPR: 2
Эта подсказка полезна при выборе источников изображений, которые соответствуют плотности пикселей экрана (например, дескрипторы x в атрибуте srcset).
Ширина
Подсказка Width появляется в запросах на получение графических ресурсов, которые отправляются тегами <img> или <source> с помощью атрибута sizes.
sizes сообщает браузеру, каким будет внешний размер ресурса, а Width использует этот внешний размер, чтобы запросить изображение с внутренним размером, оптимальным для текущего макета.
Например, пользователь запрашивает страницу на экране шириной 320 пикселей CSS с DPR, равным 2. Устройство загружает документ с элементом <img>, содержащим значение атрибута sizes, равное 85vw (т.е. 85 % ширины области просмотра для всех размеров экрана). Если подсказка Width включена, клиент отправит
ее Width на сервер вместе с запросом src для <img>:
Width: 544
В этом случае клиент сообщает серверу, что оптимальная внутренняя ширина запрашиваемого изображения составляет 85 % от ширины области просмотра (272 пикселя), умноженной на DPR экрана (2), что равно 544 пикселям.
Эта подсказка особенно эффективна, поскольку она не только учитывает ширину экрана с поправкой на плотность, но и согласовывает эту критически важную информацию с внешним размером изображения в макете. Это позволяет серверам согласовывать ответы с изображениями, которые оптимальны как для экрана, так и для макета.
Content-DPR
Как вы уже знаете, у экранов есть соотношение логических и физических пикселей. У ресурсов оно тоже есть. В простейших случаях соотношение пикселей между устройствами и ресурсами может быть одинаковым. Но! Если используются оба заголовка (DPR и Width), то из-за внешнего размера ресурса могут возникать ситуации, когда они различаются. Здесь и пригодится подсказка Content-DPR.
В отличие от других клиентских подсказок, Content-DPR – это не заголовок запроса, который используется серверами, а заголовок ответа, который серверы должны отправлять, когда для выбора ресурса используются подсказки DPR и Width. Значение Content-DPR должно быть результатом следующего уравнения:
Content-DPR = [Размер ресурса выбранного изображения] / ([Width] / [DPR])
Когда отправляется заголовок запроса Content-DPR, браузер понимает, как масштабировать изображение с учетом соотношения пикселей устройства и макета. Без него изображения могут масштабироваться неправильно.
Device-Memory
Технически это часть Device Memory API. Device-Memory показывает приблизительный объем памяти текущего устройства в гибибайтах:
Device-Memory: 2
Возможный вариант использования этой подсказки – уменьшить объем кода JavaScript, отправляемого в браузеры на устройствах с ограниченным объемом памяти, поскольку JavaScript – это самый ресурсоемкий тип контента, который обычно загружают браузеры. Или вы можете отправлять изображения с более низким DPR, поскольку для их декодирования требуется меньше памяти.
Подсказки по сетям
Network Information API предоставляет другую категорию клиентских подсказок, которые описывают производительность сетевого подключения пользователя. На мой взгляд, это самый полезный набор подсказок. С их помощью мы можем адаптировать работу сайта для пользователей, меняя способ доставки ресурсов клиентам с медленным подключением.
RTT
Подсказка RTT содержит приблизительное время прохождения сигнала в миллисекундах на прикладном уровне. Подсказка RTT, в отличие от RTT транспортного уровня, включает время обработки на сервере.
RTT: 125
Эта подсказка полезна, поскольку задержка влияет на скорость загрузки.
Используя подсказку RTT, мы можем принимать решения на основе скорости отклика сети, что может помочь ускорить доставку всего контента (например, за счет пропуска некоторых запросов).
Прием данных
Хотя задержка важна для производительности загрузки, пропускная способность также имеет значение. Подсказка Downlink, выраженная в мегабитах в секунду (Мбит/с), показывает приблизительную скорость скачивания для подключения пользователя:
Downlink: 2.5
В сочетании с RTT Downlink может быть полезен для изменения способа доставки контента пользователям в зависимости от качества сетевого подключения.
ECT
Подсказка ECT означает эффективный тип подключения. Его значение выбирается из списка типов подключения, каждый из которых описывает подключение в пределах заданных диапазонов значений RTT и Downlink.
Этот заголовок не объясняет, каков фактический тип подключения. Например, он не сообщает, является ли ваш шлюз вышкой сотовой связи или точкой доступа Wi-Fi. Вместо этого он анализирует задержку и пропускную способность текущего подключения и определяет, на какой профиль сети оно больше всего похоже. Например, если вы подключитесь к медленной сети Wi-Fi, в поле ECT может быть указано значение 2g, которое наиболее точно описывает эффективное подключение.
ECT: 2g
Допустимые значения для ECT: 4g, 3g, 2g и slow-2g. Эту подсказку можно использовать в качестве отправной точки для оценки качества подключения, а затем уточнить с помощью подсказок RTT и Downlink.
Save-Data
Save-Data – это не столько подсказка, описывающая условия сети, сколько предпочтение пользователя, указывающее, что страницы должны отправлять меньше данных.
Я предпочитаю классифицировать Save-Data как сетевую подсказку, потому что многие действия, которые вы будете с ней выполнять, похожи на другие сетевые подсказки. Пользователи также могут включать его в средах с высокой задержкой или низкой пропускной способностью. Если подсказка есть, она всегда выглядит так:
Save-Data: on
Мы уже рассказывали, что можно делать с помощью Save-Data.
Это может значительно повлиять на эффективность. Это сигнал, когда пользователи
буквально просят вас отправлять им меньше писем! Если вы прислушаетесь к этому сигналу
и предпримете действия, пользователи это оценят.
Как применять теорию на практике
Что вы делаете с подсказками клиента, зависит от вас. Поскольку они предлагают так много информации, у вас есть много вариантов. Чтобы понять, как это работает, давайте посмотрим, как подсказки клиента могут помочь Sconnie Timber, вымышленной лесозаготовительной компании, расположенной в сельской местности на Верхнем Среднем Западе. Как это часто бывает в отдалённых районах, сетевые подключения могут быть нестабильными. Именно в таких случаях технология подсказок клиента может быть очень полезна.
Адаптивные изображения
Все, кроме самых простых вариантов использования адаптивных изображений, может усложниться. Что, если у вас есть несколько вариантов обработки и вариантов одних и тех же изображений для разных размеров экрана и разных форматов? Такая разметка очень быстро становится очень сложной.
Легко ошибиться, забыть или неправильно понять важные концепции (например, sizes).
Хотя <picture> и srcset – отличные инструменты, их разработка и поддержка для сложных сценариев использования могут занять много времени. Мы можем автоматизировать создание разметки, но это также сложно, поскольку функции, предоставляемые <picture> и srcset, достаточно сложны, поэтому их автоматизация должна выполняться таким образом, чтобы сохранить гибкость, которую они предоставляют.
Подсказки клиента могут упростить эту задачу. Согласование ответов с изображениями с помощью подсказок клиента может выглядеть примерно так:
- Если это применимо к вашему рабочему процессу, сначала выберите обработку изображения (например, художественное изображение), проверив подсказку
Viewport-Width. - Выбрать разрешение изображения, проверив подсказки
WidthиDPRи выбрав источник, который соответствует размеру макета изображения и плотности экрана (аналогично тому, как дескрипторыxиwработают вsrcset). - Выбирайте наиболее оптимальный формат файла, поддерживаемый браузером (в большинстве браузеров это можно сделать с помощью
Accept).
Для своей вымышленной лесозаготовительной компании я разработал простую процедуру выбора адаптивных изображений на PHP, которая использует подсказки клиента. Это означало, что вместо отправки этой разметки всем пользователям:
<picture>
<source
srcset="
company-photo-256w.webp 256w,
company-photo-512w.webp 512w,
company-photo-768w.webp 768w,
company-photo-1024w.webp 1024w,
company-photo-1280w.webp 1280w
"
type="image/webp"
/>
<img
srcset="
company-photo-256w.jpg 256w,
company-photo-512w.jpg 512w,
company-photo-768w.jpg 768w,
company-photo-1024w.jpg 1024w,
company-photo-1280w.jpg 1280w
"
src="company-photo-256w.jpg"
sizes="(min-width: 560px) 251px, 88.43vw"
alt="The Sconnie Timber Staff!"
/>
</picture>
Мне удалось сократить его до следующего, исходя из поддержки отдельных браузеров:
<img
src="/image/sizes:true/company-photo.jpg"
sizes="(min-width: 560px) 251px, 88.43vw"
alt="SAY CHEESY PICKLES."
/>
В этом примере URL /image – это PHP-скрипт, за которым следуют параметры, перезаписанные с помощью mod_rewrite. Он принимает название файла изображения и дополнительные параметры, которые помогают серверному скрипту выбрать оптимальное изображение для заданных условий.
"Но разве это не просто повторная реализация <picture> и srcset на сервере?" – это ваш первый вопрос.
В некотором смысле да, но с важным отличием: когда приложение использует подсказки клиента для создания медиа-ответов, большую часть (если не всю) работы гораздо проще автоматизировать, что может включать в себя сервис (например, CDN), который может сделать это от вашего имени. В случае с HTML-решениями для каждого варианта использования нужно писать новую разметку. Да, вы можете автоматизировать создание разметки. Однако если ваш дизайн или требования изменятся, скорее всего, вам придется пересмотреть свою стратегию автоматизации в будущем.
Подсказки клиента позволяют начать с изображения высокого разрешения без потерь, размер которого затем можно динамически изменять, чтобы он был оптимальным для любого сочетания экрана и макета. В отличие от srcset, где вам нужно перечислить фиксированный список возможных вариантов изображений, из которых браузер будет выбирать, этот подход может быть более гибким. Если при использовании srcset вы вынуждены предлагать браузерам ограниченный набор вариантов (например, 256w, 512w, 768w и 1024w), то решение на основе подсказок клиента позволяет обслуживать все варианты ширины без огромного количества разметки.
Конечно, вам не обязательно писать логику выбора изображений самостоятельно. Cloudinary использует подсказки клиента для создания изображений, когда вы используете параметр w_auto. В результате медианный объем скачиваемых данных в браузерах с поддержкой подсказок клиента снизился на 42 %.
Но будьте осторожны! В версии Chrome 67 для компьютеров была удалена поддержка междоменных подсказок клиента. К счастью, эти ограничения не распространяются на мобильные версии Chrome и будут полностью сняты для всех платформ, когда будет завершена работа над правилами функций.
Как помочь пользователям с медленным интернетом
Адаптивная производительность – это идея о том, что мы можем корректировать способ доставки ресурсов на основе информации, которую нам предоставляют подсказки клиента, в частности информации о текущем состоянии сетевого подключения пользователя.
Что касается сайта Sconnie Timber, мы принимаем меры по снижению нагрузки при медленном подключении к сети, проверяя заголовки Save-Data, ECT, RTT и Downlink в коде серверной части. После этого мы генерируем оценку качества сети, которую можно использовать, чтобы определить, нужно ли вмешаться для улучшения пользовательского опыта. Оценка сети находится в диапазоне от 0 до 1, где 0 – наихудшее качество сети, а 1 – наилучшее.
Сначала мы проверяем, есть ли Save-Data. Если да, то оценка устанавливается на уровне 0, поскольку мы предполагаем, что пользователь хочет, чтобы мы сделали все необходимое для облегчения и ускорения работы.
Если же подсказка Save-Data отсутствует, мы переходим к оценке значений подсказок ECT, RTT и Downlink, чтобы рассчитать показатель, описывающий качество сетевого подключения. Исходный код для оценки сетей доступен на GitHub. Вывод заключается в том, что если мы будем использовать подсказки, связанные с сетью, некоторым образом, мы сможем улучшить работу тех, кто находится в медленных сетях.
Если сайты адаптируются к информации, которую предоставляют подсказки клиента, нам не нужно применять подход "все или ничего". Мы можем разумно решить, какие ресурсы отправить. Мы можем изменить логику выбора адаптивных изображений, чтобы отправлять изображения более низкого качества для данного дисплея, чтобы ускорить загрузку при низком качестве сети.
В этом примере мы видим, как подсказки клиента влияют на производительность сайтов в медленных сетях. Ниже показана каскадная диаграмма WebPagetest для сайта в медленной сети, который не адаптируется к подсказкам клиента:
А теперь посмотрим на каскадную диаграмму для того же сайта и того же медленного подключения, но на этот раз сайт использует клиентские подсказки, чтобы исключить некритичные ресурсы страницы:
Благодаря подсказкам клиента время загрузки страницы сократилось с 45 секунд до менее чем 4,5 секунды. Преимущества подсказок клиента в этом сценарии невозможно переоценить, и они могут стать серьезным благом для пользователей, ищущих важную информацию в медленных сетях.
Кроме того, подсказки клиента можно использовать, не нарушая работу браузеров, которые их не поддерживают. Например, если мы хотим настроить доставку ресурсов, используя значение подсказки ECT, но при этом обеспечить полную функциональность для неподдерживаемых браузеров, мы можем установить возврат к значению по умолчанию следующим образом:
// Set the ECT value to "4g" by default.
$ect = isset($_SERVER["HTTP_ECT"]) ? $_SERVER["HTTP_ECT"] : "4g";
Здесь "4g" – это самое высокое качество сетевого подключения, описанное в заголовке ECT. Если мы инициализируем $ect как "4g", это не повлияет на браузеры, которые не поддерживают подсказки клиента. Согласие — это победа!
Не забывайте о тайниках!
Если вы меняете ответ на основе HTTP-заголовка, вам нужно знать, как кеш будет обрабатывать будущие запросы этого ресурса. Заголовок Vary здесь незаменим, поскольку он связывает записи кеша со значениями заголовков запросов, которые ему передаются. Проще говоря, если вы изменяете ответ на основе определенного заголовка HTTP-запроса, то почти всегда должны включать запрос этого заголовка в Vary, например:
Vary: DPR, Width
Однако есть важное условие: никогда не используйте Vary для кешируемых ответов в часто меняющемся заголовке (например, Cookie), поскольку такие ресурсы фактически становятся некешируемыми. Поэтому лучше не
Varyполагаться на заголовки клиентских подсказок, такие как RTT или Downlink, поскольку они
связаны с подключением и могут часто меняться. Если вы хотите изменить ответы в этих заголовках, рекомендуем использовать только заголовок ECT, чтобы минимизировать количество случаев, когда в кеше нет совпадений.
Конечно, это применимо только в том случае, если вы кэшируете ответ.
Например, не стоит кешировать HTML-объекты с динамическим контентом, поскольку это может ухудшить взаимодействие с пользователем при повторных посещениях. В таких случаях вы можете изменять ответы по своему усмотрению, не обращая внимания на Vary.
Подсказки клиенту в сервисных воркерах
Согласование контента теперь доступно не только для серверов. Поскольку сервисные скрипты действуют как прокси-серверы между клиентами и серверами, вы можете контролировать доставку ресурсов с помощью JavaScript. в том числе подсказки клиента. В событии fetch сервисного скрипта вы можете использовать метод request.headers.get объекта event, чтобы прочитать заголовки запроса ресурса, например:
self.addEventListener('fetch', (event) => {
let dpr = event.request.headers.get('DPR');
let viewportWidth = event.request.headers.get('Viewport-Width');
let width = event.request.headers.get('Width');
event.respondWith(
(async function () {
// Do what you will with these hints!
})(),
);
});
Таким образом можно прочитать любой заголовок подсказки клиента, который вы включили. Однако это не единственный способ получить такую информацию. Подсказки, относящиеся к сети, можно прочитать в следующих эквивалентных свойствах JavaScript в объекте navigator:
| Подсказка клиента | Эквивалент в JS |
|---|---|
| `ECT` | `navigator.connection.effectiveType` |
| `RTT` | `navigator.connection.rtt` |
| `Save-Data` | `navigator.connection.saveData` |
| `Downlink` | `navigator.connection.downlink` |
| `Device-Memory` | `navigator.deviceMemory` |
Поскольку эти API доступны не везде, вам нужно проверить их наличие с помощью оператора in:
if ('connection' in navigator) {
// Work with netinfo API properties in JavaScript!
}
Здесь вы можете использовать логику, аналогичную той, которую вы использовали бы на сервере, за исключением того, что вам не нужен сервер для согласования контента с подсказками клиента. Сервис-воркеры могут ускорить работу сайта и сделать его более надежным, поскольку они могут показывать контент, когда пользователь находится в офлайн-режиме.
Завершение
С помощью подсказок клиента мы можем сделать работу пользователей быстрее и полностью прогрессивной. Мы можем показывать медиаконтент с учетом возможностей устройства пользователя, что упрощает показ адаптивных изображений по сравнению с использованием <picture> и srcset, особенно в сложных случаях. Это позволяет нам не только сократить время и усилия на разработку, но и оптимизировать ресурсы, особенно изображения, таким образом, чтобы они лучше соответствовали экранам пользователей, чем это возможно с помощью
Что ещё важнее, мы можем выявлять плохое сетевое подключение и помогать пользователям, изменяя то, что мы отправляем, и то, как мы это отправляем. Это может значительно упростить доступ к сайтам для пользователей с нестабильным подключением к интернету. В сочетании с сервис-воркерами это позволяет создавать невероятно быстрые сайты, доступные в офлайн-режиме.
Хотя подсказки клиента доступны только в Chrome и браузерах на основе Chromium, их можно использовать так, чтобы не мешать работе браузеров, которые их не поддерживают. Используйте подсказки клиента, чтобы создавать по-настоящему инклюзивные и адаптируемые интерфейсы, учитывающие возможности устройств пользователей и сетей, к которым они подключаются. Надеюсь, другие разработчики браузеров увидят их ценность и захотят внедрить.
Ресурсы
- Автоматические адаптивные изображения с клиентскими подсказками
- Подсказки клиента и адаптивные изображения – что изменилось в Chrome 67
- Подсказки клиента (Презентации)
- Как создавать быстрые и легкие приложения с помощью
Save-Data
Благодарим Илью Григорика (Ilya Grigorik), Эрика Портиса (Eric Portis), Джеффа Посника (Jeff Posnick), Йоава Вайса (Yoav Weiss) и Эстель Вейл (Estelle Weyl) за ценные отзывы и правки к этой статье.