Чёткость до последнего байта: как делать веб-графику хорошо — часть 1
По-серьёзному о графике в интернете: основы форматов изображений, инструменты для оптимизации и то, как люди воспринимают веб-графику.
Мы заботливо подготовили перевод крутой статьи от наших коллег из блога Evil Martians (оригинал материала авторства Полины Гуртовой, Риты Клубочкиной и Энди Барнова ищите здесь). Статья будет полезна фронтендерам, ПМ-мам, контентщикам и вообще всем, кто имеет дело с изображениями в интернетах (возможно, даже вашей маме).
Знаете ли вы, что средняя веб-страница для десктопа в 2019 занимала 2 МБ трафика, и половина всего, что веб-сервер отправляет браузеру пользователя, — это графика? JPEG, PNG, SVG, GIF и некоторые другие аббревиатуры известны каждому, кто когда-либо создавал хоть что-либо в «цифре». Может показаться, что всё отображаемое на странице касается только фронтенд-разработки, но на самом деле понимание специфики веб-изображений важно для всех членов продуктовой группы: от тех, кто отвечает за серверную часть, до дизайнеров, менеджеров и специалистов техподдержки клиентов.
Вместо тысячи слов
Если у вас не так много времени, чтобы читать эту длинную и извилистую статью, вот инфографика.
Встретились как-то в баре… кривая и цветовая кодировка
Технически гипертекст (текст, который ссылается на другой текст), представленный Дугласом Энгельбартом в 1968 году как основа современной веб-коммуникации, не нуждается в изображениях для передачи информации. Но реальность такова, что вниманием пользователя нужно управлять с помощью графического контента. Изображения, видео, CSS-анимация, рисованная графика Canvas API, WebGL, даже Flash — тёмная технология древних времен — все средства хороши в постоянной борьбе за удержание пользователя.
Для компьютера каждое изображение — это просто последовательность конкретных инструкций. То, как они переводятся в аппаратные пиксели, отображаемые на экране, — само по себе захватывающая история. Большинство форматов изображений, за исключением BMP (кто там
в пейнте ещё рисует?), в точности не хранит значения пикселей. Немножко математики, и данные, содержащиеся в файле, декодируются в массив значений с цветовой кодировкой. Кодировка RGB (red, green, blue) — самая очевидная для передачи цвета.
Кодировка YCbCr тоньше, поскольку учитывает работу человеческого глаза и мозга: на самом деле мы более восприимчивы к изменениям яркости, чем к изменениям цвета.
Когда мы имеем дело с векторной графикой, то особенно не задумываемся о тройных или четверных кодировках (CMYK), как в растровых форматах. Больше интересуют геометрические примитивы: линии, круги и квадраты, которые по факту являются просто кривыми Безье.
PNG, GIF, JPEG, WebP, HEIC, AVIF (для видео) — растровые форматы, SVG — векторный формат. Ниже о каждом будет поподробнее.
Для примера — большое изображение
Исходный размер изображения ниже, полученного на профессиональную видеокамеру — 37,8 МБ. Из уважения к вашему интернет-провайдеру, его сжали его до 3,5 МБ без потери качества.
Но оптимизация самого изображения — это не первое, что стоит учитывать при работе с визуальным контентом в интернете. Для начала, оцените весь стек, стоящий за доставкой этих сочных байтов по сети к конечному пользователю. Для этого задайте себе пару вопросов:
- Загружаете ли вы все изображения одновременно или сосредотачиваетесь только на тех, которые должны отображаться в первую очередь (используете Lazy Loading)?
- Думали ли вы про HTTP/2, который поддерживает мультиплексирование (передачу нескольких потоков данных с меньшей скоростью по одному каналу) на уровне протокола?
- Вы эффективно сжимаете ваши файлы?
Запишите эти вопросы себе шпаргалочкой, а теперь — поговорим о самих изображениях.
Ничто не совершенно
Ваша ответственность перед пользователями в том, чтобы предоставить им изображения самого высокого качества, используя при этом минимум ресурсов: вычислительной мощности (как сервера, так и клиента), памяти компьютера и пропускной способности канала связи.
Мы будем говорить о техническом качестве изображения и не будем учитывать композицию, перспективу или цветовую гармонию. Просто представим, что у нас уже есть идеальное изображение, которое нужно разместить в интернете самым оптимальным способом.
Качество изображения — степень, в которой полученное изображение отличается от идеального. И под качеством имеется в виду следующее:
Резкость
Точность цветопередачи
Отсутствие артефактов
Глаза, мозг и контекст
Как фронтенд-разработчик, верстающий макет в HTML и CSS, или как дизайнер, создающий этот макет, вы решаете одну и ту же проблему: иллюстрируете некоторую концепцию для ваших пользователей с помощью изображений. Поэтому они имеют значение ещё до того, как вы начнете применять какие-то инструменты. Например:
На первой картинке изображение — ключевой контент: мы ожидаем, что пользователь потратит некоторое время на его просмотр, поэтому нам нужно максимально возможное качество. На второй картинке текст важнее. Картинка там для антуража, поэтому её можно сжать по-максимуму, и никто не заметит.
На третьем изображении — интерактивный элемент, где и текст, и изображение одинаково важны, поскольку они требуют действий пользователя. Такие элементы должны быть масштабируемыми, «многоразовыми» и занимать как можно меньше места, поэтому имеет смысл отказаться от растра в пользу вектора.
Другой критический фактор — человеческое восприятие. Яркость и контрастность важнее цвета, поэтому на нём можно сэкономить (и, опять же, никто не заметит).
Также следует помнить, что разные экраны и разные браузеры отображают графику немного по-разному. Иногда уловить это почти невозможно (особенно, если у вас нет экрана Retina), а учитывать — стоит:
Не все пиксели созданы равными
Что такое пиксель, в конце концов? Сейчас даже малыш, который некоторое время смотрел «Свинку Пеппу» на родительском телефоне, вероятно, имеет некоторое представление об этом. Однако всё не то, чем кажется.
Когда мы говорим «пиксель», то на самом деле имеем в виду одну из, по крайней мере, трех совершенно разных вещей:
- точку в аппаратном смысле,
- точку в смысле CSS,
- точку в смысле «данных изображения».
Самый хитрый из них — это так называемый пиксель CSS. Его описывают как единицу длины, которая приблизительно равна ширине или высоте одной точки, которую человеческий глаз может комфортно видеть без напряжения.
Когда вы читаете текст на своем телефоне, вы держите экран на определенном расстоянии от глаз, но когда вы смотрите на экран компьютера, вы стараетесь отодвинуться подальше, чтобы читать было удобно. Чем больше расстояние между сетчаткой и экраном, тем больше будет размер «пикселя CSS».
Не вдаваясь в подробности, мы можем просто помнить, что «физический размер» пикселя CSS — это неизменное значение в миллиметрах, своё для каждого типа экрана. На экранах Apple Retina (iPhone, iPad, Mac) это значение варьируется от 0,11 до 0,23 мм. Даже не спрашивайте нас о форме пикселя (это сложный вопрос!), просто помните — используется одно значение, а не набор чисел.
Пиксель CSS также не совпадает с аппаратным пикселем — тот является минимальным размером точки в соответствии с физическими характеристиками конкретного экрана.
Теперь мы можем наконец поговорить о device pixel ratio (DPR) — соотношении пикселей устройства. Понимание DPR чрезвычайно важно, если вы хотите, чтобы ваши изображения выглядели одинаково хорошо на всех устройствах.
Вы можете открыть вкладку DevTools в любом браузере (нажмите F12), который вы используете прямо сейчас, и набрать devicePixelRatio, чтобы узнать DPR вашего текущего экрана. При этом, если перетащить окно на другой экран (например, на внешний дисплей) — значение обновится. Оно рассчитывается по формуле:
Возьмем изображение с шириной 1000 пикселей и высотой 1000 пикселей.
Поместим его на странице:
Установив width равным 1000px, вы говорите браузеру отображать 1000*1000 = 1 млн пикселей CSS. Если DPR (соотношение пикселей вашего устройства) равно единице (экран — не Retina), то задействуется 1000 * 1 * 1000 * 1 = 1 млн аппаратных пикселей.
Один аппаратный пиксель отвечает за один пиксель «изображения», как и должно быть интуитивно.
Но что, если у вас Retina, и DPR=2? Теперь ваше изображение отображается с помощью 1000 * 2 * 1000 * 2 = 4 млн аппаратных пикселей. Это означает, что один пиксель вашего изображения отображается четырьмя аппаратными пикселями. Иными словами, изображение масштабируется: каждый пиксель его данных «растягивается» для отображения на экране.
Маленький пиксель в большом мире
Как мы выяснили, размеры изображения иногда не соответствуют аппаратному обеспечению один к одному. А поскольку браузеры не могут определить содержание растрового изображения, они используют универсальные алгоритмы (математика!), чтобы подгадать лучшую стратегию изменения размера. И, как вы можете догадаться, они не всегда угадывают правильно.
Вы можете управлять этим процессом с помощью CSS-свойства image-rendering (отображение изображения). Оно помогает задать стратегию, но вы по-прежнему не можете контролировать конкретный алгоритм, выбранный браузером.
При масштабировании области 4px до 16px в браузере доступно только четыре пикселя изображения, остальные 12 необходимо угадать. Размытые края и другие артефакты — результат такого «угадывания» или интерполяции, выполняемой алгоритмом изменения размера.
Ваша цель в том, чтобы избежать вот такого масштабирования любым способом:
- Постарайтесь понять контекст изображения и установить приемлемое качество.
- Измените размер оригинальной картинки на max_size_of_your_container * DPR.
- Подготовьте несколько версий изображений для большинства распространенных DPR (равному 1, 2 и даже 3).
- Учтите это в вашей разметке:
SVG: очень хорошее масштабирование
SVG — это масштабируемая векторная графика. Так что по определению SVG-изображения не боятся масштабирования. Почему?
Взглянем поближе на анатомию файла SVG. Во-первых, содержимое написано в виде простого текста, который читается человеком и подозрительно напоминает старый-добрый XML.
Ниже — печенька, созданная при помощи простых геометрических фигур, и экспортированная в виде svg-файла:
Пока её нельзя увидеть. Вместо этого — набор тегов:
- <svg> — это контейнер для нашей картинки,
- <g> — единица композиции (на самом деле этот тег бесполезен в примере кода выше, он только для демонстрации),
- <ellipse>, <path> — геометрические примитивы. <path> — самая универсальная форма, которую можно использовать для всех других фигур (круги, треугольники, сложные кривые).
Внешний вид фигуры определяется атрибутами. В нашем примере rx, d, cx, и другие подобные атрибуты отвечают за размер и положение. Это координаты, но не в системе координат экрана — они рассчитываются относительно параметра viewBox у SVG-изображения. В нашем случае:
viewBox="0 0 200 120″
Это значит, что изображение имеет отступ в 0 пикселей слева и 0 пикселей сверху, ширину 200 пикселей и высоту 120 пикселей. Это размер и расположение области просмотра, в которой находится наше изображение. Наш SVG также имеет width- и height-атрибуты — они определяют реальный размер самого изображения. В нашем случае это будет 200×120 CSS-пикселей (картинка 1).
Удалим width- и height-атрибуты. Теперь размер нашего изображения определяется размером окна браузера (картинка 2). Другой способ установить размер для изображения — задать width и/или height в CSS. Например:
Теперь размер изображения составляет 20% от высоты окна браузера (картинка 3). Но подождите, почему наше печенье расположено по центру? Причина — еще один атрибут, который называется preserveAspectRatio. Его значение по умолчанию — xMidYMid meet. Это значит: сохранить исходные пропорции изображения, сохранить содержимое текущего viewBox видимым, масштабировать изображение как можно больше, центрировать результат как по вертикали, так и по горизонтали. Но если поиграть с его значениями, получится три разных результата — картинки 4−6.
А если нам нужна только половинка печенья, можно просто уменьшить ширину viewBox (картинка 6):
Используя атрибуты viewBox и preserveAspectRatio вместе, можно масштабировать изображения миллионами способов.
Скрытые способности SVG
Помимо тегов, кривых и координат, SVG скрывает ещё некоторые сюрпризы. Во-первых, вы можете поместить растровые изображения внутрь. Этот прием полезен, если нужно добавить интерактивность к другому растровому изображению или как-то пометить его. Поэтому всегда проверяйте, а действительно ли SVG-изображение, с которым вы имеете дело, векторное.
Во-вторых, мы можем анимировать пафы (<path>) внутри SVG-изображения, и сделать само изображение анимированным.
Наконец, SVG-файлы могут быть опасны. Ничто не мешает кому-то поместить тег <script> и немного JavaScript в синтаксис XML. А браузер запустит этот код. Так что соблюдайте осторожность при работе с SVG из ненадежных источников и тщательно проверяйте, что там внутри.
SVG против растровых форматов
Ну ок, SVG-изображения имеют суперспособности. Но должны ли мы всегда использовать их для простой графики? Нет! Использование SVG дает нам файл с изображением печеньки в 26 КБ, в то время как растровый WebP (подробнее о нем позже) того же изображения умещается в 16 КБ. И если нет никакой разницы, зачем платить больше?
Вы можете работать с SVG — создавать и редактировать его — прямо в консоли браузера. Но удобнее и профессиональнее заняться этим в редакторе векторных изображений. Например, в Boxy SVG с полным набором опций для работы с векторной графикой, а также встроенным редактором кода, если очень хочется поковыряться.
А теперь пришло время оптимизировать SVG-изображение с помощью svgo. Благодаря этому можно получить SVG-файл в 13 Кб вместо растрового файла формата WebP в 16 Кб. Вектор снова выиграл!
Поскольку изображения SVG — это просто текстовые файлы, они очень хорошо сжимаются. Мы ещё раз повторим: «Идеального формата не существует», но вы можете выбрать подходящий формат для вашей задачи и применить столько оптимизаций, сколько захотите.
На самом интересном месте останавливаемся — впереди вторая часть материала, в которой подробно расскажем о сжатии изображений, особенностях растровых форматов и о том, как их использовать в интернете.
Полезная статья, спасибо 👍
Ребят, это перезалив? Кажется, что вы уже публиковали эту статью
Спасибо, ждем продолжение