Pull to refresh
128.25
Домклик
Место силы

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

Level of difficultyEasy
Reading time6 min
Views11K

Привет, меня зовут Денис, я руковожу направлением разработки в Домклик. Дополнительно несу ношу лидера frontend-направления в нашей компании. Не так давно я отрефакторил систему собеседований для frontend-разработчиков, попутно тестируя технические вопросы на внешних и внутренних респондентах. И пришёл к выводу, что множество мной опрошенных разработчиков, вне зависимости от уровня, не знают или просто не обращают внимание на базовые правила при работе с картинками. В результате на просторах интернета зачастую можно найти изображения размером 200 на 200 пикселей и весом в несколько мегабайтов со смещением макета, столь раздражающим пользователей. Если вам интересно, как практически без вложений улучшить пользовательский опыт, то прошу под кат.

Содержание:

  • Исходные данные и выбор основного формата

  • Изменение размеров

  • Оптимизация

  • WebP

  • Тег picture и srcset

  • Предзагрузка

  • Ленивая загрузка

  • Сдвиг макета

  • Object-fit

Исходные данные и выбор основного формата

Для того, чтобы статья была наглядной и последовательной, я взял из одного из проектов моей команды картинку размером 1600 x 484 пикселей. Оригинал в png весит 1,1 Mб, а оригинал в jpg весит 807 Kб. Здесь впору задать себе вопрос, нужен ли альфа-канал? Если нужен, берём png, в противном случае берём jpg, так как он меньше весит, а качество визуально идентично в подавляющем большинстве случаев. Для следующих двух пунктов нам потребуется инструмент для изменения размеров и оптимизации изображений. Существует колоссальное количество инструментов как онлайн, так и десктопных. Лично я использую iLoveIMG, но вас, разумеется, это никак не должно ограничивать. Для конвертации исходных изображений в формат WebP использую cloudconvert.

Изменение размеров

Начнём с того, зачем менять разрешение и когда это необходимо. Благодаря этому мы можем сделать картинку легче и тем самым повысить скорость её загрузки. Если мы не собираемся использовать нашу картинку как фон во весь экран, а, например, хотим показать в блоке с размерами 400x121, то необходимо уменьшить её до размера (400x121)*2, чтобы картинка не стала выглядеть хуже на дисплеях с увеличенной плотностью пикселей, таких как Retina. Чтобы потом не возвращаться к этой главе, сразу предлагаю сделать картинки для обычных дисплеев размером 400x121. Будем ли мы их использовать, зависит от многих «но» и «если», но об этом позже. Ниже приведена таблица с разрешением и весом после изменения разрешения.

Формат

Разрешение

Вес

png

1600 x 484

1,1 Mб

jpg

1600 x 484

807 Kб

png

800 x 242

279 Kб

jpg

800 x 242

245 Kб

png

400 x 121

74 Kб

jpg

400 x 121

66 Kб

Оптимизация

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

Формат

Разрешение

Вес

png

1600 x 484

312 Kб

jpg

1600 x 484

177 Kб

png

800 x 242

82 Kб

jpg

800 x 242

52 Kб

png

400 x 121

22 Kб

jpg

400 x 121

15 Kб

WebP

Что такое WebP, вы можете узнать из других статей, но если в двух словах: это уже устоявшийся формат изображений. Его преимущество в том, что весит он меньше, чем аналоги, сохраняет хорошее качество изображения и альфа-канал. Большинство браузеров уже давно поддерживают этот формат, но даже если вам нужно поддержать старый браузер, то всегда можно воспользоваться запасным вариантом, о котором я расскажу в  следующей главе. Что ж, конвертировав исходные png-изображения в WebP можем получить такие результаты.

Разрешение

Вес

1600 x 484

89 Kб

800 x 242

23 Kб

400 x 121

7 Kб

Тег picture и srcset

Мы можем использовать picture для того, чтобы:

  1. Добавить запасной вариант для браузеров, не понимающих формат WebP.

  2. Дать браузеру возможность выбрать максимально подходящую картинку для отображения.

В пример ниже мы сообщаем браузеру о том, что ему следует использовать для дисплеев Retina изображения с разрешением 800x242, а для обычных — 400x121. Если браузер умеет работать с WebP, то использовать именно этот формат, иначе — png.

<picture>
  <source srcset="800x242.webp 2x, 400x121.webp 1x" type="image/webp"/>
  <img src="400x121.png" srcset="800x242.png 2x" alt="house"/>
</picture>

Но, как говорил Иван Васильевич: «есть нюанс». Об этом самом нюансе пойдёт речь в следующей главе. 

Предзагрузка

Есть такая метрика веб-производительности, как Largest Contentful Paint (LCP). Она означает длительность загрузки самого большого визуального элемента в той области, которую видит пользователь при попадании на страницу. И, конечно же, при обнаружении изображения Lighthouse собирает с него метрики. Чтобы улучшить этот показатель, мы с вами уже изменили размер изображения, оптимизировали его и даже добавили WebP. Но есть ещё способ улучшить метрику, а именно: предварительно загрузить изображение. Делается это с помощью тега link в заголовке страницы:

<link rel="preload" as="image" type="image/webp" href="/800x242.webp"/>

Эта подсказка браузеру повышает приоритет загрузки изображения, а также начинает его загрузку ещё до обнаружения элемента img в DOM. И тут мы как раз подходим к нюансу. Если у нас были разные изображения для Retina и прочих дисплеев, то с предварительной загрузкой на текущий момент времени мы должны чётко знать, что и зачем загружаем. Проблема в ограниченной поддержке атрибута srcset для тега link. В данном случае лучше предварительно загрузить WebP с двойной плотностью пикселей и использовать эту картинку как для Retina, так и для обычных дисплеев. А код с запасным вариантом будет выглядеть немного проще.

<picture>
  <source srcset="800x242.webp" type="image/webp"/>
  <img src="800x242.png" alt="house"/>
</picture>

Ленивая загрузка

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

  1. атрибут loading со значением lazy в теге img

  2. intersectionObserver API

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

Что касается intersectionObserver API, то процесс появления изображения лежит уже на наших плечах, и расстояние до контента задаём мы сами. А недостаток в том, что придётся написать пару строчек кода на JavaScript, к тому же этот вариант будет в любом случае подсовывать поисковикам либо неправильную ссылку на изображение, либо изображение будет отсутствовать в разметке вовсе. Но если вас не заботит SEO, то это не проблема.

Сдвиг макета

Ещё одна из важнейших, по моему мнению, метрик из семейства web performance: это Cumulative Layout Shift (CLS). Она разделяет второе место по значимости вместе с Largest Contentful Paint(LCP) и имеет вес в 25 баллов в Lighthouse v10. Взглянем на пример ниже.

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

Так вот, очень важно указывать изображениям ширину (width) и высоту (height), это верный способ избежать смещения макета. А также поможет ленивой загрузке правильно высчитать расстояние до картинки. В результате после добавления картинке значений ширины и высоты сдвиг макета более не побеспокоит пользователей.

Object-fit

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

Если вам нужно отображать картинки разной ширины и высоты, условно, в квадрате, то рекомендую использовать свойство object-fit со значением cover. Изображение без нарушения пропорций заполнит всю доступную область, с обрезкой всего, что не влезет. 

Если важная часть изображения частично или полностью исчезла из области видимости, как на скриншоте выше, то мы можем позиционировать изображение при помощи свойства object-position.

Выводы

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

Tags:
Hubs:
Total votes 54: ↑50 and ↓4+46
Comments21

Articles

Information

Website
domclick.ru
Registered
Founded
Employees
501–1,000 employees
Location
Россия
Representative
Евгения Макарова