Мы уже давно используем адаптивные изображения picture с srcset, но захотелось реализовать ленивую загрузку изображений на проектах, когда юзер видит изображение в плохом качестве, пока загружается основное. В наше время пользователи хотят получать как можно больше контента за как можно меньшее время. В связи с этим, если изображение загружается не мгновенно, это уже проблема. Пользователь, скорее всего, его пропустит и пройдет дальше, если вообще не закроет сайт. Вариант с отображением анимированного блока или изображения худшего качества в момент загрузки, очевидно, привлекает пользователей сильнее, чем просто белый блок. Поэтому решили, что его и будем реализовывать. Однако, есть множество различных способов это сделать. Какие варианты мы рассматривали? Плюсы: очень простая имплементация требует немного ресурсов Минусы: в 2023 выглядит достаточно скучно и не цепляет внимание (не вызывает желание дождаться окончания загрузки) Отображение сжатого до 1-2kb изображения с наложенным blur эффектом. Вроде отличная идея... Плюсы: такие изображения загружаются почти мгновенно. Минусы: т.к. изображения для размеров экранов в desktop, tablet и mobile могут отличаться (размер, соотношение сторон, сам контент изображений), возникает необходимость присылать из api base64 изображение для каждого разрешения экрана. Это кратно увеличивает размер json'a (особенно, если мы запрашиваем страницу каталога, каждая карточка в которой содержит слайдер из множества картинок). Примерно так у нас сейчас выглядит объект картинки: Добавлять base64 строку под каждое разрешение представляется не лучшей идеей, поэтому идем дальше. Это относительно новая технология загрузки jpeg изображений, когда картинка загружается не линейно (сверху вниз), а сразу заполняет все пространство блока и загружается в несколько слоев (от самого худшего качества до наилучшего). Изображение из статьи Тем не менее, есть несколько нюансов, которые заставляют поискать что-то еще: это jpeg, никакой другой формат изображений так не может, а значит, мы вынуждены отказаться от других форматов (например, webp или avif), хотя JPEG по-прежнему является доминирующей технологией для хранения цифровых изображений, он не отвечает нескольким требованиям, которые стали важными в последние годы, например, сжатие изображений с более высокой битовой глубиной (от 9 до 16 бит), изображения с высоким динамическим диапазоном, без потерь. сжатие и представление альфа-каналов. Это тот вариант, на котором мы остановились. Blurhash — это библиотека, разработанная крутыми ребятами с имплементацией на любой язык Мы получаем короткую строку (20–30 символов) в формате base83, и «натягиваем» ее на канвас. Плюсы: данный формат позволяет сократить вес json’а до минимума нет необходимости добавлять лишние стили для заблюривания картинки нет необходимости присылать несколько вариантов изображения для разных экранов (desktop, tablet, mobile) изображение имеет «мягкие» очертания будущего контента Минусы: необходимость использования canvas и довольно сильное размытие контента Прежде чем переходить к реализации на фронте, мы реализовали небольшой микросервис, который вы можете поднять из docker образа, который сможет генерировать base83 для ваших картинок. Микросервис доступен в репозитории. Наша имплементация Разработчики любезно предоставили нам библиотеку react-blurhash, которая имеет уже адаптированные компоненты для работы с blurhash. Приблизительный вид json, который получает этот компонент: В целом, нет острой необходимости присылать изображения для разных разрешений ( и разных форматов). Достаточно изменить типизацию и заменить рукописный копмонент Picture на любой другой Image для вашего варианта использования. В данном контексте нас интересует лишь поле: Оно и является нашей строкой blurhash (длину строки можно регулировать при кодировании, изменяя соотношение сторон и размер исходного изображения). По умолчанию изображение не содержит данных В момент, когда оно попадает в зону видимости пользователя, срабатывает useEffect, выполняющий set данных в компонент Picture и накладывающий поверх него canvas c blurhash Когда изображение полностью загружено, canvas плавно прячется Сам компонент: Задаем базовый флаг isLoaded для изменения стилей и контроля за состоянием загрузки. imgPlaceholder — это и есть строка blurhash; imageSrc — сюда будет «сетиться» ссылка на исходное изображение (по дефолту пустая строка. или, как в нашем случае, объект из нескольких полей); imageRef — для отслеживания попадания картинки в область видимости юзера; onLoad — хендлер успешной загрузки изображения. Добавляем useEffect, который и выполняет всю работу: Используем IntersectionObserver для отслеживания попадания изображения в зону видимости, когда это происходит — сетим данные в Picture и отменяем подписку. Собственно jsx: Здесь используется styled-components, но это не принципиально. StyledLazyImage — div контейнер, его стили: Blurhash — это компонент библиотеки react-blurhash, его пропсы: Name Description  hash (string) The encoded blurhash string.  width (int | string) Width (CSS) of the decoded image.  height (int | string) Height (CSS) of the decoded image.  resolutionX (int) The X-axis resolution in which the decoded image will be rendered at. Recommended min. 32px. Large sizes (>128px) will greatly decrease rendering performance. (Default: 32)  resolutionY (int) The Y-axis resolution in which the decoded image will be rendered at. Recommended min. 32px. Large sizes (>128px) will greatly decrease rendering performance. (Default: 32)  punch (int) NControls the "punch" value (~contrast) of the blurhash decoding algorithm. (Default: 1)  StyledBlurhash — контейнер для компонента Blurhash, его стили: Скорость и плавность скрытия Blurhash можно регулировать через transition и animation. Picture — компонент картинки (его можно заменить на NextImage или любой другой, он должен возвращать image). Он принимает ссылки на все типы изображений и сетит их в <picture/> Данный компонент был имплементирован в уже готовый проект с множеством изображений в различных слайдерах и блочных моделях. Задача была - реализовать максимально адаптивный вариант без внешних исправлений верстки. Сейчас мы пробуем эту реализацию на других проектах и фидбек положительный, что не может не радовать. Подробный пример реализации на React можно посмотреть здесь. Микросервис на Go для получения blurhash из картинок — здесь.  Руковожу студией веб-разработки в Минске