Как стать автором
Обновить
2755.78
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Вывод чётких изображений на экранах с высокой плотностью пикселей

Время на прочтение11 мин
Количество просмотров12K
Автор оригинала: Jake Archibald
Много лет тому назад существовали мониторы с разными разрешениями, а после того, как индустрия перешагнула отметку в 1024x768, экраны, с увеличением разрешения, становились больше.

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

Далее, в 2010 году, вышел iPhone 4 (ёшкин кот, 11 лет назад), разрешение его экрана составляло 640x960. А в iPhone 3 имелся экран почти такого же размера, но с разрешением 320x480. Разрешение выросло вдвое, а физический размер экрана остался примерно таким же, как раньше. В результате вдвое выросла плотность пикселей экрана.



Нельзя было, без изменений, запускать старые приложения на новых экранах, так как нечто вроде текстов и кнопок выглядело бы слишком маленьким. Поэтому компания Apple удвоила (Прим.: справедливости ради, в 4 раза) размеры всех экранных элементов. 1 логический пиксель превратился в 2 физических пикселя.

В веб-разработке соотношение логических и физических пикселей известно как DPR (Device Pixel Ratio). DPR iPhone 4 равняется 2 (иногда такие экраны называют «2x-экранами» или «2dppx-экранами»).

Теперь, немного коснувшись истории, перейдём к более современным вещам.

Насколько популярны экраны с высокой плотностью пикселей?


Мэтт Хоббс, который занимается проектом gov.uk, любезно предоставил мне данные за апрель 2021 года по плотности пикселей экранов устройств посетителей сайта. Я поработал с этими данными и оказалось, что 80% пользователей ресурса применяют устройства, DPR которых составляет 1,5 и выше. А именно:

  • Это — более 99,9% их пользователей, применяющих мобильные телефоны.
  • Это — 32% их пользователей с обычными компьютерами.
  • Это — 78% их пользователей, работающих с ресурсом на планшетах.

Конечно, gov.uk — это сайт, ориентированный, в основном, на Великобританию, но его аудиторию составляют широкие слои населения страны. Это — не только «технари» и богатые люди. Полагаю, на основе вышеприведённых данных мы можем с высокой долей уверенности в своей правоте сделать следующие выводы:

  • Пользователи, применяющие устройства, для которых характерна небольшая область просмотра веб-контента, скорее всего будут работать с этим контентом на экранах с высокой плотностью пикселей, если только речь не идёт о сайтах, ориентированных на простые мобильные телефоны.
  • Пользователи, устройства которых отличаются большой областью просмотра контента, с меньшей долей вероятности будут обладателями экранов с высокой плотностью пикселей, но их число растёт, если только речь не идёт о сайтах, ориентированных, в основном, на бюджетные устройства.

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

Зачем ориентироваться на нужды экранов с высокой плотностью пикселей?


Всё, что видит пользователь, за исключением растровых рисунков, будет, в любом случае, рендериться с использованием полной доступной плотности пикселей, включая текст, SVG-изображения, интерфейс браузера. В результате, если рисунок не рассчитан на экран с высокой плотностью пикселей, он может выглядеть размытым или низкокачественным.

Вот пара изображений. Первое — это пример того, о чём идёт речь. Второе — пример более качественного изображения.


0,5x-изображение


1x-изображение

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

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

Сжатие изображений для экранов с высокой плотностью пикселей


Вот — 1x-версия нашего изображения шириной 400 пикселей.


1x-изображение (WebP, качество 80, размер 14,9 Кб) / запасная ссылка

Я преобразовал изображение в формат WebP с уровнем качества 80. Если попробовать более низкий уровень качества — начнутся потери серьёзных деталей изображения. Размер графического файла составляет 14,9 Кб. Неплохо!

Если я попробую, пользуясь теми же настройками, сделать 2x-версию того же изображения, его размер уже будет составлять 45,2 Кб. Это довольно много. Количество пикселей, формирующих изображение, выросло в 4 раза. Но нужно ли, создавая такой вариант изображения, пользоваться старыми настройками?

Вот — пара вариантов 2x-изображения.

Примечание: Эти два изображения надо вывести в таком же размере, что и предыдущее.


2x-изображение (WebP, качество 80, размер 45,2 Кб) / запасная ссылка


2x-изображение (WebP, качество 44, размер 21,2 Кб) / запасная ссылка

На мой взгляд, 2x-версия изображения, размер файла которого составляет 21,2 Кб, выглядит достаточно хорошо. Это — не то же самое, что и картинка размером 45,2 Кб, но сжатие эту картинку не испортило.

Попробуем рассмотреть фрагменты этих двух 2x-изображений, увеличенных в два раза, что позволит просмотреть их в виде, соответствующем CSS-пикселям.

Примечание: исходные файлы тут те же, что и в двух предыдущих примерах, но они при выводе на страницу должны быть увеличены в 2 раза.


2x-изображение (WebP, качество 80, размер 45,2 Кб), увеличенное в 2 раза / запасная ссылка


2x-изображение (WebP, качество 44, размер 21,2 Кб), увеличенное в 2 раза / запасная ссылка

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

Человеческие глаза — это чудной инструмент. Он достаточно хорош для того чтобы оценить качество изображения высокой чёткости, но совсем не так хорошо выявляет артефакты сжатия. В частности — в «высокочастотных» областях изображения, там, где близлежащие пиксели отличаются сильными перепадами яркости.

Для того чтобы получить 2x-изображение, я воспользовался Squoosh.app и уменьшал его оригинал до тех пор, пока оно не приняло размер, в котором оно будет выводиться на странице. Потом я просто понижал уровень качества до тех пор, пока не ухудшился внешний вид изображения.

В результате оказалось, что можно перейти от 1x-изображения, размер файла которого составляет 14,9 Кб, к 2x-изображению с файлом размером в 21,2 Кб, и при этом, сильно выиграв в резкости изображения, не слишком серьёзно увеличить размеры его файла.

Для экранов, обладающих ещё более высокой плотностью пикселей, качество можно понижать ещё сильнее, но не так сильно, как при переходе от 1x-варианта к 2x-варианту, поэтому в данном случае игра не всегда стоит свеч.

Итак, это была теория. Как, воспользовавшись тем, что мы узнали, организовать работу с изображениями на реальных веб-страницах?

Подготовка 1x- и 2x-изображений — это не всегда просто и понятно


Вот — код, демонстрирующий схему описания простого отзывчивого изображения:

<img
  srcset="
    image-700.jpg   700w,
    image-1000.jpg 1000w,
    image-1300.jpg 1300w,
    image-1600.jpg 1600w
  "
  sizes="…"
  alt="…"
/>

У меня есть достаточно подробная статья про отзывчивые изображения. Если рассказать о них буквально в двух словах, то окажется, что атрибут srcset сообщает браузеру о том, какие версии изображения, имеющие разную ширину в пикселях, имеются в его распоряжении. Атрибут sizes сообщает браузеру о размере элемента <img> в CSS-пикселях.

Получается, что браузер может выбирать подходящее изображение, рассуждая примерно следующим образом: «Так, это изображение будет выведено в элементе шириной 500 CSS-пикселей, но сделано это будет на 2x-экране, поэтому я загружу изображение image-1000.jpg». Замечательно!

Правда, всё не так уж и замечательно. Предположим, мы подготовили изображение image-1000.jpg в расчёте на то, что оно будет выводиться на мобильном устройстве с экраном, отличающимся высокой плотностью пикселей. Поэтому мы сохранили это изображение в низком качестве. На мобильном устройстве результат будет очень хорошим, пользователь увидит резкое изображение, на загрузку которого не потребуется много трафика. Но, к несчастью, браузер может выбрать то же самое изображение на настольном устройстве с 1x-экраном, и выглядеть это изображение будет плохо, вроде вышеприведённого увеличенного изображения красной панды.

Это значит, что большинство сайтов загружает изображения, которые на 100% «тяжелее», в плане размеров файлов, чем надо, и под удар, в основном, попадают мобильные пользователи, так как скорость их связи с интернетом, весьма вероятно, может оказаться достаточно низкой.

Как решить эту проблему?

«Ленивое» решение


Расскажу о приёме, которым я пользуюсь, готовя большинство изображений для моего блога. Я беру максимальный размер изображения в CSS-пикселях, в котором оно может быть выведено, после чего умножаю этот размер на 2. Потом я кодирую изображение в пониженном качестве, так как оно всегда будет выводиться в режиме с плотностью пикселей 2x или выше. Вот так. И это всё.

В случае с «большими» изображениями для постов вроде этого, мои изображения выводятся в полном размере в том случае, если размер области просмотра имеет ширину 799px. В результате ширину изображений в пикселях я делаю равной 1598.

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

<picture>
  <source type="image/avif" srcset="red-panda.avif" />
  <source type="image/webp" srcset="red-panda.webp" />
  <img src="red-panda.jpg" width="1598" height="1026" alt="A red panda" />
</picture>

Вот — варианты этого изображения в разных форматах.


Изображение в формате JPEG (размер файла — 99,2 Кб)


Изображение в формате WebP (размер файла — 57,5 Кб) / запасная ссылка


Изображение в формате AVIF (размер файла — 37,5 Кб) / запасная ссылка

Этот метод далёк от идеала. Размер WebP-файла составляет 57,5 Кб, но мы уже видели, что изображение такого формата, со знанием дела оптимизированное для мобильных устройств, занимает 21,2 Кб. Налицо серьёзная разница в размерах файлов. Правда, большая часть пользователей загрузит AVIF-файл, размер которого составляет 37,5 Кб. И тут ещё нужно учесть нагрузку на систему, связанную с декодированием достаточно крупных изображений, но… но…

В общем-то, я просто ищу оправдание своей лени. Но, как я уже говорил, эти изображения тщательно оптимизированы, чего не скажешь о большинстве изображений в вебе. Если вы, работая с изображениями, поступите примерно так, как поступаю с ними я, это значит, что вы уже будете обходиться с картинками гораздо лучше, чем обходятся создатели большинства веб-сайтов. Если вы читали мои статьи про оптимизацию сайтов команд Формулы-1, то вам должно быть известно, что размеры файлов многих изображений, близких по пиксельным размерам к моим, превышают 300 Кб.

Но не будем руководствоваться ленью. Сделаем всё как нужно.

Полноценное решение


Итак, нам нужно отдавать браузерам различные варианты изображений, рассчитанных на экраны, плотность пикселей которых превышает 1x. Теги <picture> и <source>, к счастью, позволяют нам это сделать.

<picture>
  <source media="(-webkit-min-device-pixel-ratio: 1.5)" srcset="…" sizes="…" />
  <img srcset="…" sizes="…" width="1598" height="1026" alt="A red panda" />
</picture>

В теге <source> используется медиазапрос (-webkit-min-device-pixel-ratio: 1.5), нацеленный на устройства, пиксельная плотность экранов которых составляет, как минимум, 1,5x. «Правильный» способ работы с изображениями, соответствующий веб-стандартам, заключается в использовании конструкции (min-resolution: 1.5x), но браузер Safari это не поддерживает. Поэтому остановимся на -webkit-min-device-pixel-ratio. Эта конструкция была добавлена в состав стандартов совместимости из-за того, что она использовалась на множестве сайтов. Теперь её поддерживают все браузеры.

А теперь нужно лишь разобраться с атрибутами sizes и srcset. В настоящий момент один и тот же блок sizes надо повторять в <img> и в каждом <source>, но я работаю над изменением спецификации, в результате настанет время, когда будет достаточно одного такого атрибута в теге <img>.

Вот как выглядит атрибут sizes для «больших» изображений из моего блога:

<picture>
  <source
    media="(-webkit-min-device-pixel-ratio: 1.5)"
    srcset="…"
    sizes="
      (min-width: 1066px) 743px,
      (min-width: 800px) calc(75vw - 57px),
      100vw
    "
  />
  <img
    srcset="…"
    sizes="
      (min-width: 1066px) 743px,
      (min-width: 800px) calc(75vw - 57px),
      100vw
    "
    width="1598"
    height="1026"
    alt="A red panda"
  />
</picture>

Всё это значит, что при ширине области просмотра в 1066px или большей, ширина изображения будет зафиксирована на значении 743px. При ширине области просмотра в 800px или больше, размер изображения будет равняться 75% ширины области просмотра за вычетом 57px. А в других случаях изображение займёт всю ширину области просмотра. Значения в sizes не обязательно должны быть, как здесь, на 100% точными, но чем они точнее — тем лучше браузер сможет выбрать подходящее изображение.

А как насчёт srcset? Тут, в случае с 1x, я могу срезать кое-какие углы. Статистические данные указывают на то, что 1x-экраны имеются, главным образом, в настольных устройствах, для которых характерны более широкие, чем у мобильных устройств, области просмотра. В данном случае я считаю, что разумно будет предположить, что область просмотра, вероятно, будет иметь ширину 1066px или больше. Поэтому тут я снова немного дам волю лени и сделаю одно изображение для 1x-пользователей шириной 743w.

<picture>
  <source
    media="(-webkit-min-device-pixel-ratio: 1.5)"
    srcset="…"
    sizes="
      (min-width: 1066px) 743px,
      (min-width: 800px) calc(75vw - 57px),
      100vw
    "
  />
  <img src="1x-743.jpg" width="743" height="477" alt="A red panda" />
</picture>

Так как в <img> имеется лишь один атрибут src, я могу избавиться тут от sizes.

Когда я сжимаю 1x-изображение в Squoosh, я довожу его размер до 100%. В результате бегунок, управляющий качеством изображения, мне приходится перетаскивать к гораздо более высоким значениям в сравнении со значениями, используемыми для 2x-изображений, о сжатии которых я рассказывал выше.

А как быть с 2x-изображениями? Ширина области просмотра экранов мобильных устройство обычно находится в районе 320-420px, поэтому я, если говорить об областях просмотра минимальной ширины, собираюсь остановиться на 800w. О том, что я выбрал для самых широких областей просмотра, я уже рассказал. Это — 1598w. У меня никогда нет полной уверенности в том, сколько промежуточных вариантов изображений нужно готовить, поэтому я сделаю лишь один такой вариант — 1200w.

<picture>
  <source
    media="(-webkit-min-device-pixel-ratio: 1.5)"
    srcset="2x-800.jpg 800w, 2x-1200.jpg 1200w, 2x-1598.jpg 1598w"
    sizes="
      (min-width: 1066px) 743px,
      (min-width: 800px) calc(75vw - 57px),
      100vw
    "
  />
  <img src="1x-743.jpg" width="743" height="477" alt="A red panda" />
</picture>

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

Но это — лишь JPEG! Добавим в наш код ещё пару форматов.

<picture>
  <source
    type="image/avif"
    media="(-webkit-min-device-pixel-ratio: 1.5)"
    srcset="2x-800.avif 800w, 2x-1200.avif 1200w, 2x-1598.avif 1598w"
    sizes="
      (min-width: 1066px) 743px,
      (min-width: 800px) calc(75vw - 57px),
      100vw
    "
  />
  <source
    type="image/webp"
    media="(-webkit-min-device-pixel-ratio: 1.5)"
    srcset="2x-800.webp 800w, 2x-1200.webp 1200w, 2x-1598.webp 1598w"
    sizes="
      (min-width: 1066px) 743px,
      (min-width: 800px) calc(75vw - 57px),
      100vw
    "
  />
  <source
    media="(-webkit-min-device-pixel-ratio: 1.5)"
    srcset="2x-800.jpg 800w, 2x-1200.jpg 1200w, 2x-1598.jpg 1598w"
    sizes="
      (min-width: 1066px) 743px,
      (min-width: 800px) calc(75vw - 57px),
      100vw
    "
  />
  <source type="image/avif" srcset="1x-743.avif" />
  <source type="image/webp" srcset="1x-743.webp" />
  <img src="1x-743.jpg" width="743" height="477" alt="A red panda" />
</picture>

Надо отметить, что этот подход реализуется гораздо проще при использовании какого-нибудь сервиса для работы с изображениями. Кстати, сайт The Guardian использует очень похожий подход, хотя решения о типах изображений принимаются на сервере с учётом браузерного заголовка Accept.

Итоги


Буду ли я, вместо «ленивого» подхода, пользоваться подходом «полноценным»? Готовя изображения для этого блога, возможно, не буду. Какая-то часть меня прямо-таки наслаждается процессом ружного сжатия изображений и их преобразования в современные форматы, но я не думаю, что готов повторять эту процедуру по 12 раз для каждой картинки. С меня хватит и 3 раз.

Правда, если бы я собрался воспользоваться каким-нибудь сервисом, который автоматически сжимает изображения, учитывая то, что результат такого сжатия будет не так хорош, как результат сжатия «ручного», полагаю, я перешёл бы на «полноценный» подход. Это позволило бы мне минимизировать объём графических данных, загружаемых пользователями, в частности — пользователями мобильных устройств.

Как вы оптимизируете изображения для своих сайтов?

Теги:
Хабы:
Всего голосов 24: ↑24 и ↓0+24
Комментарии12

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds