Создание эффективного компонента изображения

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

Лина Сохони
Leena Sohoni
Кара Эриксон
Kara Erickson
Алекс Кастл
Alex Castle

Изображения являются распространенным источником проблем с производительностью веб-приложений и ключевым направлением оптимизации. Неоптимизированные изображения способствуют раздуванию страницы и составляют более 70% общего веса страницы в байтах в 90 процентиле. Множество способов оптимизации изображений требуют интеллектуального «компонента изображения» с решениями по повышению производительности, встроенными по умолчанию.

Команда Aurora работала с Next.js над созданием одного такого компонента . Целью было создать оптимизированный шаблон изображения, который веб-разработчики могли бы дополнительно настраивать. Компонент служит хорошей моделью и устанавливает стандарт для создания компонентов изображения в других платформах, системах управления контентом (CMS) и стеках технологий. Мы сотрудничали над аналогичным компонентом для Nuxt.js и работаем с Angular над оптимизацией изображений в будущих версиях. В этом посте рассказывается о том, как мы разработали компонент изображения Next.js, и об уроках, которые мы извлекли на этом пути.

Компонент изображения как расширение изображений

Проблемы и возможности оптимизации изображений

Изображения влияют не только на производительность, но и на бизнес. Количество изображений на странице было вторым по значимости показателем конверсии пользователей, посещающих веб-сайты. В сеансах, в которых пользователи совершили конверсию, было на 38 % меньше изображений, чем в сеансах, в которых они не совершили конверсию. Lighthouse перечисляет множество возможностей для оптимизации изображений и улучшения веб-показателей в рамках своего аудита передового опыта. Ниже приведены некоторые из распространенных областей, в которых изображения могут влиять на основные веб-показатели и взаимодействие с пользователем.

Неразмерные изображения вредят CLS

Изображения, отображаемые без указания их размера, могут вызвать нестабильность макета и привести к большому совокупному сдвигу макета ( CLS ). Установка атрибутов width и height для элементов <img> может помочь предотвратить сдвиги макета. Например:

<img src="flower.jpg" width="360" height="240">

Ширина и высота должны быть установлены так, чтобы соотношение сторон визуализированного изображения было близко к его естественному соотношению сторон. Значительная разница в соотношении сторон может привести к искажению изображения. Относительно новое свойство, которое позволяет указать соотношение сторон в CSS, может помочь оперативно изменять размер изображений, предотвращая при этом CLS.

Большие изображения могут повредить LCP

Чем больше размер файла изображения, тем больше времени займет его загрузка. Большое изображение может быть «главным» изображением страницы или наиболее значимым элементом в области просмотра, ответственным за запуск отрисовки наибольшего содержимого ( LCP ). Изображение, которое является частью критического содержимого и загрузка которого занимает много времени, приведет к задержке LCP.

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

Плохое сжатие изображений может повредить LCP

Современные форматы изображений, такие как AVIF или WebP, могут обеспечить лучшее сжатие, чем обычно используемые форматы JPEG и PNG. Лучшее сжатие уменьшает размер файла на 25–50 % в некоторых случаях при том же качестве изображения. Это сокращение приводит к более быстрой загрузке с меньшим потреблением данных. Приложение должно предоставлять современные форматы изображений браузерам, поддерживающим эти форматы.

Загрузка ненужных изображений вредит LCP

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

Проблемы оптимизации

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

  • Приоритеты : веб-разработчики обычно сосредотачиваются на коде, JavaScript и оптимизации данных. Таким образом, они могут не знать о проблемах с изображениями или о том, как их оптимизировать. Изображения, созданные дизайнерами или загруженные пользователями, могут не занимать первое место в списке приоритетов.
  • Готовое решение . Даже если разработчики осведомлены о нюансах оптимизации изображений, отсутствие универсального готового решения для их фреймворка или технологического стека может стать сдерживающим фактором.
  • Динамические изображения . Помимо статических изображений, которые являются частью приложения, пользователи загружают динамические изображения или получают их из внешних баз данных или CMS. Может быть сложно определить размер таких изображений, если источник изображения является динамическим.
  • Перегрузка разметки . Решения по включению размера изображения или srcset для разных размеров требуют дополнительной разметки для каждого изображения, что может быть утомительно. Атрибут srcset был введен в 2014 году, но сегодня используется только 26,5% веб-сайтов. При использовании srcset разработчикам приходится создавать изображения разных размеров. Такие инструменты, как just-gimme-an-img, могут помочь, но их придется использовать вручную для каждого изображения.
  • Поддержка браузеров . Современные форматы изображений, такие как AVIF и WebP, создают файлы изображений меньшего размера, но требуют специальной обработки в браузерах, которые их не поддерживают. Разработчикам приходится использовать такие стратегии, как согласование контента или элемент <picture чтобы изображения доставлялись всем браузерам.
  • Сложности с отложенной загрузкой . Существует множество методов и библиотек для реализации отложенной загрузки изображений, расположенных ниже сгиба. Выбор лучшего может оказаться непростой задачей. Разработчики также могут не знать оптимальное расстояние от «сгиба» для загрузки отложенных изображений. Различные размеры области просмотра на устройствах могут еще больше усложнить эту задачу.
  • Изменение ландшафта . Поскольку браузеры начинают поддерживать новые функции HTML или CSS для повышения производительности, разработчикам может быть сложно оценить каждую из них. Например, Chrome представляет функцию «Приоритет выборки» в качестве пробной версии Origin . Его можно использовать для повышения приоритета определенных изображений на странице. В целом, разработчикам было бы проще, если бы такие улучшения оценивались и реализовывались на уровне компонентов.

Имиджевый компонент как решение

Доступные возможности оптимизации изображений и трудности их реализации индивидуально для каждого приложения привели нас к идее компонента изображения. Компонент изображения может инкапсулировать и применять лучшие практики. Заменив элемент <img> компонентом изображения, разработчики смогут лучше решить проблемы с производительностью изображений.

В течение прошлого года мы работали с инфраструктурой Next.js над разработкой и реализацией их компонента Image . Его можно использовать в качестве замены существующих элементов <img> в приложениях Next.js следующим образом.

// Before with <img> element:
function Logo() {
  return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}

// After with image component:
import Image from 'next/image'

function Logo() {
  return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}

Компонент пытается решить проблемы, связанные с изображениями, в целом, используя богатый набор функций и принципов. Он также включает параметры, которые позволяют разработчикам настраивать его в соответствии с различными требованиями к изображениям.

Защита от сдвигов планировки

Как обсуждалось ранее, изображения без размера вызывают изменения макета и способствуют CLS. При использовании компонента изображения Next.js разработчики должны указать размер изображения, используя атрибуты width и height чтобы предотвратить любые сдвиги макета. Если размер неизвестен, разработчики должны указать layout=fill для предоставления изображения без размера, которое находится внутри контейнера определенного размера. В качестве альтернативы вы можете использовать импорт статических изображений, чтобы получить размер фактического изображения на жестком диске во время сборки и включить его в образ.

// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />

// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />

// Image component with image import
import Image from 'next/image'
import logo from './logo.png'

function Logo() {
  return <Image src={logo} alt="logo" />
}

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

Облегчение реагирования

Чтобы изображения реагировали на разные устройства, разработчики должны установить атрибуты srcset и sizes в элементе <img> . Мы хотели сократить эти усилия с помощью компонента «Изображение». Мы разработали компонент изображения Next.js так, чтобы значения атрибутов устанавливались только один раз для каждого приложения. Мы применяем их ко всем экземплярам компонента Image в зависимости от режима макета. Мы придумали решение, состоящее из трёх частей:

  1. Свойство deviceSizes : это свойство можно использовать для однократной настройки точек останова на основе устройств, общих для базы пользователей приложения. Значения по умолчанию для точек останова включены в файл конфигурации.
  2. Свойство imageSizes : это также настраиваемое свойство, используемое для получения размеров изображения, соответствующих контрольным точкам размера устройства.
  3. Атрибут layout в каждом изображении: используется для указания того, как использовать свойства deviceSizes и imageSizes для каждого изображения. Поддерживаемые значения для режима макета: fixed , fill , intrinsic и responsive

Когда изображение запрашивается с режимами макета Response или Fill , Next.js идентифицирует изображение, которое будет обслуживаться, на основе размера устройства, запрашивающего страницу, и соответствующим образом устанавливает srcset и sizes изображения.

Следующее сравнение показывает, как режим макета можно использовать для управления размером изображения на разных экранах. Мы использовали демонстрационное изображение, опубликованное в документации Next.js, просмотренное на телефоне и стандартном ноутбуке.

Экран ноутбука Экран телефона
Макет = Внутренний: масштабируется до ширины контейнера на меньших окнах просмотра. Не масштабируется за пределы внутреннего размера изображения в большом окне просмотра. Ширина контейнера равна 100 %.
Изображение гор показано как естьИзображение гор уменьшено
Макет = Исправлено: изображение не реагирует. Ширина и высота фиксированы аналогично ` `элемент независимо от устройства, на котором он отображается.
Изображение гор показано как естьИзображение гор в том виде, в каком оно есть, не умещается на экране.
Макет = Адаптивный: масштабирование в зависимости от ширины контейнера в разных окнах просмотра с сохранением соотношения сторон.
Изображение гор увеличено до размера экранаИзображение гор уменьшено до размера экрана
Макет = Заливка: ширина и высота растягиваются для заполнения родительского контейнера. (В этом примере ширина родительского элемента <div> равна 300*500)
Изображение гор рендерится под размер 300*500.Изображение гор рендерится под размер 300*500.
Изображения, визуализированные для разных макетов

Обеспечьте встроенную отложенную загрузку

Компонент Image по умолчанию предоставляет встроенное высокопроизводительное решение для отложенной загрузки . При использовании элемента <img> есть несколько вариантов отложенной загрузки, но все они имеют недостатки, которые затрудняют их использование. Разработчик может использовать один из следующих подходов отложенной загрузки:

  • Укажите атрибут loading : поддерживается всеми современными браузерами .
  • Используйте API Intersection Observer . Создание собственного решения для отложенной загрузки требует усилий, а также продуманного проектирования и реализации. У разработчиков не всегда может быть на это время.
  • Импортируйте стороннюю библиотеку для отложенной загрузки изображений. Могут потребоваться дополнительные усилия для оценки и интеграции подходящей сторонней библиотеки для отложенной загрузки.

В компоненте изображения Next.js по умолчанию загрузка установлена ​​на "lazy" . Отложенная загрузка реализована с помощью Intersection Observer, который доступен в большинстве современных браузеров . Разработчикам не требуется делать ничего дополнительного, чтобы включить его, но они могут отключить его при необходимости.

Предварительная загрузка важных изображений

Довольно часто элементами LCP являются изображения, а большие изображения могут задерживать LCP. Рекомендуется предварительно загрузить важные изображения , чтобы браузер мог быстрее обнаружить их. При использовании элемента <img> подсказка о предварительной загрузке может быть включена в заголовок HTML следующим образом.

<link rel="preload" as="image" href="important.png">

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

<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />

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

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

CDN изображений рекомендуется для автоматизации оптимизации изображений, они также поддерживают современные форматы изображений, такие как WebP и AVIF. Компонент Next.js Image по умолчанию использует CDN изображений с использованием архитектуры загрузчика . В следующем примере показано, что загрузчик позволяет настраивать CDN в файле конфигурации Next.js.

module.exports = {
  images: {
    loader: 'imgix',
    path: 'https://ImgApp/imgix.net',
  },
}

При такой конфигурации разработчики могут использовать относительные URL-адреса в источнике изображения, а платформа объединит относительный URL-адрес с путем CDN для создания абсолютного URL-адреса. Поддерживаются популярные CDN изображений, такие как Imgix , Cloudinary и Akamai . Архитектура поддерживает использование специального облачного поставщика путем реализации специальной функции loader для приложения.

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

Могут возникнуть ситуации, когда веб-сайты не могут использовать CDN изображений. В таких случаях компонент изображения должен поддерживать локальные изображения. Компонент Next.js Image использует оптимизатор изображений в качестве встроенного сервера изображений, который предоставляет CDN-подобный API. Оптимизатор использует Sharp для преобразования производственных изображений, если он установлен на сервере. Эта библиотека — хороший выбор для тех, кто хочет создать собственный конвейер оптимизации изображений.

Поддержка прогрессивной загрузки

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

Компонент Next.js Image поддерживает прогрессивную загрузку изображения через свойство заполнителя . Его можно использовать как LQIP (заполнитель изображения низкого качества) для отображения изображения низкого качества или размытия во время загрузки фактического изображения.

Влияние

Благодаря включению всех этих оптимизаций мы добились успеха в производстве компонента Next.js Image, а также работаем с другими технологическими стеками над аналогичными компонентами изображений.

Когда Leboncoin перенесла свой устаревший интерфейс JavaScript на Next.js , они также обновили свой конвейер изображений, чтобы использовать компонент изображения Next.js. На странице, которая перешла с <img> на next/image, время LCP снизилось с 2,4 до 1,7 с. Общий объем байтов изображений, загруженных для страницы, увеличился с 663 КБ до 326 КБ (примерно 100 КБ байтов изображений, загруженных с отложенной загрузкой).

Извлеченные уроки

Любой, кто создает приложение Next.js, может извлечь выгоду из использования компонента Next.js Image для оптимизации. Однако, если вы хотите создать аналогичные абстракции производительности для другой платформы или CMS, следующие уроки, которые мы извлекли на этом пути, могут оказаться полезными.

Предохранительные клапаны могут принести больше вреда, чем пользы

В ранней версии компонента изображения Next.js мы предоставили атрибут unsized , который позволял разработчикам обойти требования к размеру и использовать изображения с неуказанными размерами. Мы думали, что это будет необходимо в тех случаях, когда невозможно заранее узнать высоту или ширину изображения. Однако мы заметили, что пользователи рекомендуют атрибут unsized в проблемах GitHub как универсальное решение проблем с требованиями к размеру, даже в тех случаях, когда они могут решить проблему способами, не ухудшающими CLS. Впоследствии мы объявили устаревшим и удалили атрибут unsized .

Отделите полезное трение от бессмысленного раздражения

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

Однако вы можете найти обходные пути для устранения таких проблем, не жертвуя при этом производительностью. Например, во время разработки компонента Next.js Image мы получали жалобы на то, что раздражает поиск размеров локально хранящихся изображений. Мы добавили импорт статических изображений , который упрощает этот процесс за счет автоматического получения размеров локальных изображений во время сборки с помощью плагина Babel.

Найдите баланс между удобными функциями и оптимизацией производительности.

Если ваш компонент изображения не делает ничего, кроме навязывания «полезного трения» своим пользователям, разработчики, как правило, не захотят его использовать. Мы обнаружили, что, хотя функции производительности, такие как изменение размера изображения и автоматическое создание значений srcset , были наиболее важными. Удобные функции для разработчиков, такие как автоматическая отложенная загрузка и встроенные размытые заполнители, также вызвали интерес к компоненту Next.js Image.

Создайте дорожную карту для функций, способствующих внедрению

Создать решение, которое идеально работало бы во всех ситуациях, очень сложно. Может возникнуть соблазн разработать что-то, что будет хорошо работать для 75% людей, а затем сказать остальным 25%, что «в этих случаях этот компонент не для вас».

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

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

Заключение

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

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

Компонент Next.js Image успешно улучшил производительность приложений Next.js, тем самым улучшив удобство работы с пользователем. Мы считаем, что это отличная модель, которая будет хорошо работать в более широкой экосистеме, и нам бы хотелось услышать мнение разработчиков, которые хотели бы использовать эту модель в своих проектах.

,

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

Лина Сохони
Leena Sohoni
Кара Эриксон
Kara Erickson
Алекс Кастл
Alex Castle

Изображения являются распространенным источником проблем с производительностью веб-приложений и ключевым направлением оптимизации. Неоптимизированные изображения способствуют раздуванию страницы и составляют более 70% общего веса страницы в байтах в 90 процентиле. Множество способов оптимизации изображений требуют интеллектуального «компонента изображения» с решениями по повышению производительности, встроенными по умолчанию.

Команда Aurora работала с Next.js над созданием одного такого компонента . Целью было создать оптимизированный шаблон изображения, который веб-разработчики могли бы дополнительно настраивать. Компонент служит хорошей моделью и устанавливает стандарт для создания компонентов изображения в других платформах, системах управления контентом (CMS) и стеках технологий. Мы сотрудничали над аналогичным компонентом для Nuxt.js и работаем с Angular над оптимизацией изображений в будущих версиях. В этом посте рассказывается о том, как мы разработали компонент изображения Next.js, и об уроках, которые мы извлекли на этом пути.

Компонент изображения как расширение изображений

Проблемы и возможности оптимизации изображений

Изображения влияют не только на производительность, но и на бизнес. Количество изображений на странице было вторым по значимости показателем конверсии пользователей, посещающих веб-сайты. В сеансах, в которых пользователи совершили конверсию, было на 38 % меньше изображений, чем в сеансах, в которых они не совершили конверсию. Lighthouse перечисляет множество возможностей для оптимизации изображений и улучшения веб-показателей в рамках своего аудита передового опыта. Ниже приведены некоторые из распространенных областей, в которых изображения могут влиять на основные веб-показатели и взаимодействие с пользователем.

Неразмерные изображения вредят CLS

Изображения, отображаемые без указания их размера, могут вызвать нестабильность макета и привести к большому совокупному сдвигу макета ( CLS ). Установка атрибутов width и height для элементов <img> может помочь предотвратить сдвиги макета. Например:

<img src="flower.jpg" width="360" height="240">

Ширина и высота должны быть установлены так, чтобы соотношение сторон визуализированного изображения было близко к его естественному соотношению сторон. Значительная разница в соотношении сторон может привести к искажению изображения. Относительно новое свойство, которое позволяет указать соотношение сторон в CSS, может помочь оперативно изменять размер изображений, предотвращая при этом CLS.

Большие изображения могут повредить LCP

Чем больше размер файла изображения, тем больше времени займет его загрузка. Большое изображение может быть «главным» изображением страницы или наиболее значимым элементом в области просмотра, ответственным за запуск отрисовки наибольшего содержимого ( LCP ). Изображение, которое является частью критического содержимого и загрузка которого занимает много времени, приведет к задержке LCP.

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

Плохое сжатие изображений может повредить LCP

Современные форматы изображений, такие как AVIF или WebP, могут обеспечить лучшее сжатие, чем обычно используемые форматы JPEG и PNG. Лучшее сжатие уменьшает размер файла на 25–50 % в некоторых случаях при том же качестве изображения. Это сокращение приводит к более быстрой загрузке с меньшим потреблением данных. Приложение должно предоставлять современные форматы изображений браузерам, поддерживающим эти форматы.

Загрузка ненужных изображений вредит LCP

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

Проблемы оптимизации

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

  • Приоритеты : веб-разработчики обычно сосредотачиваются на коде, JavaScript и оптимизации данных. Таким образом, они могут не знать о проблемах с изображениями или о том, как их оптимизировать. Изображения, созданные дизайнерами или загруженные пользователями, могут не занимать первое место в списке приоритетов.
  • Готовое решение . Даже если разработчики осведомлены о нюансах оптимизации изображений, отсутствие универсального готового решения для их фреймворка или технологического стека может стать сдерживающим фактором.
  • Динамические изображения . Помимо статических изображений, которые являются частью приложения, пользователи загружают динамические изображения или получают их из внешних баз данных или CMS. Может быть сложно определить размер таких изображений, если источник изображения является динамическим.
  • Перегрузка разметки . Решения по включению размера изображения или srcset для разных размеров требуют дополнительной разметки для каждого изображения, что может быть утомительно. Атрибут srcset был введен в 2014 году, но сегодня используется только 26,5% веб-сайтов. При использовании srcset разработчикам приходится создавать изображения разных размеров. Такие инструменты, как just-gimme-an-img, могут помочь, но их придется использовать вручную для каждого изображения.
  • Поддержка браузера . Современные форматы изображений, такие как AVIF и WebP, создают файлы изображений меньшего размера, но требуют специальной обработки в браузерах, которые их не поддерживают. Разработчикам приходится использовать такие стратегии, как согласование контента или элемент <picture чтобы изображения доставлялись всем браузерам.
  • Сложности с отложенной загрузкой . Существует множество методов и библиотек для реализации отложенной загрузки изображений, расположенных ниже сгиба. Выбор лучшего может оказаться непростой задачей. Разработчики также могут не знать оптимальное расстояние от «сгиба» для загрузки отложенных изображений. Различные размеры области просмотра на устройствах могут еще больше усложнить эту задачу.
  • Изменение ландшафта . Поскольку браузеры начинают поддерживать новые функции HTML или CSS для повышения производительности, разработчикам может быть сложно оценить каждую из них. Например, Chrome представляет функцию «Приоритет выборки» в качестве пробной версии Origin . Его можно использовать для повышения приоритета определенных изображений на странице. В целом, разработчикам было бы проще, если бы такие улучшения оценивались и реализовывались на уровне компонентов.

Имиджевый компонент как решение

Доступные возможности оптимизации изображений и трудности их реализации индивидуально для каждого приложения привели нас к идее компонента изображения. Компонент изображения может инкапсулировать и применять лучшие практики. Заменив элемент <img> компонентом изображения, разработчики смогут лучше решить проблемы с производительностью изображений.

В течение прошлого года мы работали с инфраструктурой Next.js над разработкой и реализацией их компонента Image . Его можно использовать в качестве замены существующих элементов <img> в приложениях Next.js следующим образом.

// Before with <img> element:
function Logo() {
  return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}

// After with image component:
import Image from 'next/image'

function Logo() {
  return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}

Компонент пытается решить проблемы, связанные с изображениями, в целом, используя богатый набор функций и принципов. Он также включает параметры, которые позволяют разработчикам настраивать его в соответствии с различными требованиями к изображениям.

Защита от сдвигов планировки

Как обсуждалось ранее, изображения без размера вызывают изменения макета и способствуют CLS. При использовании компонента изображения Next.js разработчики должны указать размер изображения, используя атрибуты width и height чтобы предотвратить любые сдвиги макета. Если размер неизвестен, разработчики должны указать layout=fill для предоставления изображения без размера, которое находится внутри контейнера определенного размера. В качестве альтернативы вы можете использовать импорт статических изображений, чтобы получить размер фактического изображения на жестком диске во время сборки и включить его в образ.

// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />

// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />

// Image component with image import
import Image from 'next/image'
import logo from './logo.png'

function Logo() {
  return <Image src={logo} alt="logo" />
}

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

Облегчение реагирования

Чтобы изображения реагировали на разные устройства, разработчики должны установить атрибуты srcset и sizes в элементе <img> . Мы хотели сократить эти усилия с помощью компонента «Изображение». Мы разработали компонент изображения Next.js так, чтобы значения атрибутов устанавливались только один раз для каждого приложения. Мы применяем их ко всем экземплярам компонента Image в зависимости от режима макета. Мы придумали решение, состоящее из трех частей:

  1. Свойство deviceSizes : это свойство можно использовать для однократной настройки точек останова на основе устройств, общих для базы пользователей приложения. Значения по умолчанию для точек останова включены в файл конфигурации.
  2. Свойство imageSizes : это также настраиваемое свойство, используемое для получения размеров изображения, соответствующих контрольным точкам размера устройства.
  3. Атрибут layout в каждом изображении: используется для указания того, как использовать свойства deviceSizes и imageSizes для каждого изображения. Поддерживаемые значения для режима макета: fixed , fill , intrinsic и responsive

Когда изображение запрашивается с режимами макета «отзывчивый» или «заливка» , Next.js идентифицирует изображение, которое будет обслуживаться, на основе размера устройства, запрашивающего страницу, и соответствующим образом устанавливает srcset и sizes изображения.

Следующее сравнение показывает, как режим макета можно использовать для управления размером изображения на разных экранах. Мы использовали демонстрационное изображение, опубликованное в документации Next.js, просмотренное на телефоне и стандартном ноутбуке.

Экран ноутбука Экран телефона
Макет = Внутренний: масштабируется до ширины контейнера на меньших окнах просмотра. Не масштабируется за пределы внутреннего размера изображения в большом окне просмотра. Ширина контейнера равна 100 %.
Изображение гор показано как естьИзображение гор уменьшено
Макет = Исправлено: изображение не реагирует. Ширина и высота фиксированы аналогично ` `элемент независимо от устройства, на котором он отображается.
Изображение гор показано как естьИзображение гор в том виде, в каком оно есть, не умещается на экране.
Макет = Адаптивный: масштабирование в зависимости от ширины контейнера в разных окнах просмотра с сохранением соотношения сторон.
Изображение гор увеличено до размера экранаИзображение гор уменьшено до размера экрана
Макет = Заливка: ширина и высота растягиваются для заполнения родительского контейнера. (В этом примере ширина родительского элемента <div> равна 300*500)
Изображение гор рендерится под размер 300*500.Изображение гор рендерится под размер 300*500.
Изображения, визуализированные для разных макетов

Обеспечьте встроенную отложенную загрузку

Компонент Image по умолчанию предоставляет встроенное высокопроизводительное решение для отложенной загрузки . При использовании элемента <img> есть несколько вариантов отложенной загрузки, но все они имеют недостатки, которые затрудняют их использование. Разработчик может использовать один из следующих подходов отложенной загрузки:

  • Укажите атрибут loading : поддерживается всеми современными браузерами .
  • Используйте API Intersection Observer . Создание собственного решения для отложенной загрузки требует усилий, а также продуманного проектирования и реализации. У разработчиков не всегда может быть на это время.
  • Импортируйте стороннюю библиотеку для отложенной загрузки изображений. Могут потребоваться дополнительные усилия для оценки и интеграции подходящей сторонней библиотеки для отложенной загрузки.

В компоненте изображения Next.js по умолчанию загрузка установлена ​​на "lazy" . Отложенная загрузка реализована с помощью Intersection Observer, который доступен в большинстве современных браузеров . Разработчикам не требуется делать ничего дополнительного, чтобы включить его, но они могут отключить его при необходимости.

Предварительная загрузка важных изображений

Довольно часто элементами LCP являются изображения, а большие изображения могут задерживать LCP. Рекомендуется предварительно загрузить важные изображения , чтобы браузер мог быстрее обнаружить их. При использовании элемента <img> подсказка о предварительной загрузке может быть включена в заголовок HTML следующим образом.

<link rel="preload" as="image" href="important.png">

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

<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />

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

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

CDN изображений рекомендуется для автоматизации оптимизации изображений, они также поддерживают современные форматы изображений, такие как WebP и AVIF. Компонент Next.js Image по умолчанию использует CDN изображений с использованием архитектуры загрузчика . В следующем примере показано, что загрузчик позволяет настраивать CDN в файле конфигурации Next.js.

module.exports = {
  images: {
    loader: 'imgix',
    path: 'https://ImgApp/imgix.net',
  },
}

При такой конфигурации разработчики могут использовать относительные URL-адреса в источнике изображения, а платформа объединит относительный URL-адрес с путем CDN для создания абсолютного URL-адреса. Поддерживаются популярные CDN изображений, такие как Imgix , Cloudinary и Akamai . Архитектура поддерживает использование специального облачного поставщика путем реализации специальной функции loader для приложения.

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

Могут возникнуть ситуации, когда веб-сайты не могут использовать CDN изображений. В таких случаях компонент изображения должен поддерживать локальные изображения. Компонент Next.js Image использует оптимизатор изображений в качестве встроенного сервера изображений, который предоставляет CDN-подобный API. Оптимизатор использует Sharp для преобразования производственных изображений, если он установлен на сервере. Эта библиотека — хороший выбор для тех, кто хочет создать собственный конвейер оптимизации изображений.

Поддержка прогрессивной загрузки

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

Следующая компонент изображения. Это можно использовать в качестве LQIP (низкокачественный заполнитель изображения) для отображения низкокачественного или размытого изображения, в то время как фактическое изображение загружается.

Влияние

Со всеми этими оптимизациями мы наблюдаем успех с компонентом изображения hearl.js в производстве, а также работаем с другими техническими стеками над аналогичными компонентами изображения.

Когда Leboncoin мигрировал свой Legacy JavaScript Frontend на next.js , они также обновили свой конвейер изображений, чтобы использовать компонент изображения healh.js. На странице, которая мигрировала с <img> на следующее/изображение, LCP снизился с 2,4 до 1,7. Общее изображение байты, загруженные для страницы, прошли с 663 КБ до 326 КБ (с ~ 100 КБ байтов с ленивым нагруженным изображением).

Извлеченные уроки

Любой, кто создает приложение Next.js, может извлечь выгоду из использования компонента изображения Next.js для оптимизации. Однако, если вы хотите создать аналогичные абстракции производительности для другой структуры или CMS, ниже приведены несколько уроков, которые мы извлекли по пути, которые могут быть полезными.

Предохранительные клапаны могут нанести больший вред, чем пользы

В раннем выпуске компонента изображения Next.js мы предоставили unsized атрибут, который позволил разработчикам обходить требования по размеру и использовать изображения с неопределенными измерениями. Мы думали, что это будет необходимо в тех случаях, когда было невозможно заранее узнать высоту или ширину изображения. Тем не менее, мы заметили, что пользователи рекомендовали unsized атрибут в вопросах GitHub в качестве решения всех проблем с требованиями размеров, даже в тех случаях, когда они могли решить проблему таким образом, чтобы не ухудшиться CLS. Впоследствии мы устарели и удалили unsized атрибут.

Отдельное полезное трение от бессмысленного раздражения

Требование по размеру изображения является примером «полезного трения». Он ограничивает использование компонента, но обеспечивает огромные преимущества производительности в обмене. Пользователи с готовностью примут ограничение, если у них есть четкое представление о потенциальных преимуществах производительности. Поэтому стоит объяснить этот компромисс в документации и другие опубликованные материалы о компоненте.

Тем не менее, вы можете найти обходные пути для такого трения, не жертвуя производительностью. Например, во время разработки компонента Image Next.js мы получили жалобы на то, что это раздражало искать размеры для локально хранимых изображений. Мы добавили статический импорт изображений , который оптимизирует этот процесс, автоматически извлекая размеры для локальных изображений во время сборки с помощью плагина Babel.

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

Если ваш компонент изображения не делает ничего, кроме как навязывать «полезное трение» на своих пользователей, разработчики, как правило, не захотят его использовать. Мы обнаружили, что, хотя функции производительности, такие как размер изображения и автоматическая генерация значений srcset , были наиболее важными. Удобные функции разработчиков, такие как автоматическая ленивая загрузка и встроенные размытые заполнители, также вызвали интерес к компоненту изображения healh.js.

Установите дорожную карту для функций для управления принятием

Создание решения, которое отлично подходит для всех ситуаций, очень сложно. Может быть заманчиво спроектировать что -то, что хорошо работает для 75% людей, а затем сказать другим 25%, что «В этих случаях этот компонент не для вас».

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

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

Заключение

Использование изображения и оптимизация сложны. Разработчики должны найти баланс между производительностью и качеством изображений, обеспечивая отличный пользовательский опыт. Это делает оптимизацию изображения дорогостоящим, высокоэффективным усилием.

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

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

,

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

Лина Сохони
Leena Sohoni
Кара Эриксон
Kara Erickson
Алекс Касл
Alex Castle

Изображения являются общим источником узких мест производительности для веб -приложений и ключевой фокусировкой для оптимизации. Неоптимизированные изображения вносят вклад в раздувание страницы и составляют более 70% от общего веса страниц в байтах на 90 процентиле. Несколько способов оптимизации изображений вызывают интеллектуальный «компонент изображения» с помощью производительности, запеченных в качестве по умолчанию.

Команда Aurora работала с Next.js , чтобы построить один такой компонент . Цель состояла в том, чтобы создать оптимизированный шаблон изображения, который веб -разработчики могут дополнительно настроить. Компонент служит хорошей моделью и устанавливает стандарт для создания компонентов изображения в других структурах, системах управления контентом (CMS) и технологий. Мы сотрудничали в аналогичном компоненте для nuxt.js, и мы работаем с угловой оптимизацией изображений в будущих версиях. В этом посте обсуждается, как мы разработали компонент следующего.js изображения и уроки, которые мы извлекли по пути.

Компонент изображения как расширение изображений

Проблемы и возможности оптимизации изображений

Изображения не только влияют на производительность, но и на бизнес. Количество изображений на странице было вторым величайшим предиктором конверсий пользователей, посещающих веб -сайты. Сессии, в которых конвертировались пользователи, имели на 38% меньше изображений, чем сеансы, где они не конвертировали. Lighthouse перечисляет множество возможностей для оптимизации изображений и улучшения жизненно важных веществ в рамках его аудита. Некоторые из общих областей, где изображения могут влиять на основные веб -жизненные силы, а пользовательский опыт заключается в следующем.

Unsized изображения повредят CLS

Изображения, подаваемые без указанного размера, могут вызвать нестабильность макета и внести свой вклад в высокий совокупный сдвиг макета ( CLS ). Установка атрибутов width и height на элементах <img> может помочь предотвратить смены макета. Например:

<img src="flower.jpg" width="360" height="240">

Ширина и высота должны быть установлены так, чтобы соотношение сторон визуализированного изображения близко к его естественному соотношению сторон. Значительная разница в соотношении сторон может привести к искажению изображения. Относительно новое свойство, которое позволяет вам указать, что аспект в CSS может помочь в размерах изображений ответственно при предотвращении CLS.

Большие изображения могут повредить LCP

Чем больше размер файла изображения, тем дольше потребуется для загрузки. Большое изображение может быть изображением «героя» для страницы или наиболее значимым элементом в сборе просмотра, ответственного за запуск самой большой довольной краски ( LCP ). Изображение, которое является частью критического контента и занимает много времени для загрузки, задержит LCP.

Во многих случаях разработчики могут уменьшить размеры изображений за счет лучшего сжатия и использования адаптивных изображений. Атрибуты srcset и sizes Attributes of element element справляются <img> для предоставления файлов изображений с разными размерами. Затем браузер может выбрать правильный в зависимости от размера экрана и разрешения.

Плохое сжатие изображения может повредить LCP

Современные форматы изображений, такие как AVIF или WebP, могут обеспечить лучшее сжатие, чем обычно используемые форматы JPEG и PNG. Лучшее сжатие уменьшает размер файла на 25-50% в некоторых случаях для того же качества изображения. Это сокращение приводит к более быстрому загрузке с меньшим потреблением данных. Приложение должно служить современным форматам изображений в браузеры, которые поддерживают эти форматы.

Загрузка ненужных изображений болит LCP

Изображения ниже сгиба или нет в точке зрения не отображаются пользователю при загрузке страницы. Они могут быть отложены, чтобы они не способствовали LCP и задерживали его. Ленивая загрузка может быть использована для загрузки таких изображений позже, когда пользователь прокручивается к ним.

Проблемы оптимизации

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

  • Приоритеты : веб -разработчики обычно склонны фокусироваться на коде, JavaScript и оптимизации данных. Таким образом, они могут не знать о проблемах с изображениями или о том, как их оптимизировать. Изображения, созданные дизайнерами или загруженные пользователями, могут не быть высокими в списке приоритетов.
  • Из-за коробки решения : даже если разработчики знают о нюансах оптимизации изображений, отсутствие все в одном из ящиков для их структуры или технологического стека может быть сдерживающим фактором.
  • Динамические изображения : в дополнение к статическим изображениям, которые являются частью приложения, динамические изображения загружаются пользователями или получены из внешних баз данных или CMS. Может быть сложно определить размер таких изображений, где источник изображения является динамичным.
  • Перегрузка разметки : решения для включения размера изображения или srcset для разных размеров требуют дополнительной разметки для каждого изображения, которые могут быть утомительными. Атрибут srcset был введен в 2014 году, но сегодня используется только 26,5% веб -сайтов. При использовании srcset разработчики должны создавать изображения в разных размерах. Такие инструменты, как Just-Gimme-An-Img, могут помочь, но должны использоваться вручную для каждого изображения.
  • Поддержка браузера : современные форматы изображений, такие как Avif и Webp, создают меньшие файлы изображений, но нуждаются в специальной обработке в браузерах, которые не поддерживают их. Разработчики должны использовать такие стратегии, как переговоры о контенте или элемент <picture чтобы изображения обслуживались всем браузерам.
  • Ленивые сложности для загрузки : существует несколько методов и библиотек, доступных для реализации ленивой загрузки для изображений ниже размера. Выбор лучшего может быть проблемой. Разработчики также могут не знать наилучшее расстояние от «сгиба» для загрузки отложенных изображений. Различные размеры просмотра на устройствах могут еще больше усложнить это.
  • Изменение ландшафта . Поскольку браузеры начинают поддерживать новые функции HTML или CSS для повышения производительности, разработчикам может быть трудно оценить каждый из них. Например, Chrome представляет функцию приоритета извлечения в качестве исследования происхождения . Его можно использовать для повышения приоритета конкретных изображений на странице. В целом, разработчикам будет проще, если бы такие улучшения были оценены и реализованы на уровне компонентов.

Компонент изображения в качестве решения

Возможности, доступные для оптимизации изображений, и задач в реализации их индивидуально для каждого приложения, привели нас к идее компонента изображения. Компонент изображения может инкапсулировать и обеспечивать лучшие практики. Заменив элемент <img> компонентом изображения, разработчики могут лучше решать свои проблемы с производительностью изображения.

За последний год мы работали с Framework Next.js для разработки и реализации их компонента изображения . Он может быть использован в качестве замены для существующих элементов <img> в приложениях next.js следующим образом.

// Before with <img> element:
function Logo() {
  return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}

// After with image component:
import Image from 'next/image'

function Logo() {
  return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}

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

Защита от смены макета

Как обсуждалось ранее, неостановленные изображения вызывают сдвиги макета и способствуют CLS. При использовании компонента изображения Next.js разработчики должны предоставить размер изображения, используя атрибуты width и height чтобы предотвратить любые сдвиги макета. Если размер неизвестен, разработчики должны указать layout=fill чтобы обслуживать необозначное изображение, которое находится в контейнере размера. В качестве альтернативы вы можете использовать статический импорт изображений, чтобы получить размер фактического изображения на жестком диске во время сборки и включить его в изображение.

// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />

// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />

// Image component with image import
import Image from 'next/image'
import logo from './logo.png'

function Logo() {
  return <Image src={logo} alt="logo" />
}

Поскольку разработчики не могут использовать компонент изображения Unszed, дизайн гарантирует, что они потребуют время, чтобы рассмотреть размер изображения и предотвратить сдвиги макета.

Облегчить отзывчивость

Чтобы сделать изображения, отвечающими на устройства, разработчики должны установить атрибуты srcset и sizes в элементе <img> . Мы хотели уменьшить эти усилия с помощью компонента изображения. Мы разработали компонент изображения heall.js, чтобы установить значения атрибута только один раз на приложение. Мы применяем их ко всем экземплярам компонента изображения на основе режима макета. Мы придумали решение из трех частей:

  1. Свойство deviceSizes : Это свойство может использоваться для настройки точек останова в одноразовом на основе устройств, общих для базы пользователя приложения. Значения по умолчанию для точек останова включены в файл конфигурации.
  2. Свойство imageSizes : Это также настраиваемое свойство, используемое для получения размеров изображения, соответствующих точкам размер устройства.
  3. Атрибут layout в каждом изображении: это используется для того, чтобы указать, как использовать свойства deviceSizes и imageSizes для каждого изображения. Поддерживаемые значения для режима макета fixed , fill , intrinsic и responsive

Когда изображение запрашивается с помощью режимов макета, отзывчивых или заполнения , Next.js идентифицирует изображение, которое будет обслуживаться на основе размера устройства, запрашивающего страницу, и устанавливает srcset и sizes на изображении соответствующим образом.

Следующее сравнение показывает, как можно использовать режим макета для управления размером изображения на разных экранах. Мы использовали демонстрационное изображение, используемое в Docs Next.js, просмотрено на телефоне и стандартном ноутбуке.

Экран ноутбука Экран телефона
Layout = Intrinsic: масштабируется вниз, чтобы соответствовать ширине контейнера на небольших видовых точках. Не масштабируется за пределы внутреннего размера изображения на большем просмотре. Ширина контейнера на 100%
Горы изображение показано как естьМаунтиновое изображение уменьшилось
Mayout = фиксирован: изображение не отзывчиво. Ширина и высота фиксируются аналогично ` `Элемент независимо от устройства, где оно отображается.
Горы изображение показано как естьИзображение горы показано как это, не подходит для экрана
Layout = отзывчивый: масштабировать или масштабировать в зависимости от ширины контейнера на разных видовых точках, поддерживая соотношение сторон.
Изображение горы масштабируется, чтобы соответствовать экрануИзображение горы уменьшается вниз, чтобы соответствовать экрану
Layout = Fill: ширина и высота растянуты для заполнения родительского контейнера. (Родитель <div> Ширина установлена ​​на 300*500 в этом примере)
Изображение горы, отображаемое размером 300*500Изображение горы, отображаемое размером 300*500
Изображения, отображаемые для разных макетов

Обеспечить встроенную ленивую загрузку

Компонент изображения обеспечивает встроенное, исполнительное ленивое нагрузочное решение в соответствии с по умолчанию. При использовании элемента <img> есть несколько вариантов для ленивой загрузки, но у всех есть недостатки, которые делают их хитрыми в использовании. Разработчик может принять один из следующих ленивых подходов к загрузке:

  • Укажите атрибут loading : это поддерживается во всех современных браузерах .
  • Используйте API API Observer Insection : Создание пользовательского решения для ленивого загрузки требует усилий и вдумчивого дизайна и реализации. Разработчики не всегда могут иметь время для этого.
  • Импортируйте стороннюю библиотеку в изображения Lazy Moad: могут потребоваться дополнительные усилия для оценки и интеграции подходящей сторонней библиотеки для ленивой загрузки.

В следующем компоненте изображения holday загрузка установлена ​​на "lazy" по умолчанию. Ленивая загрузка реализована с использованием пересечения наблюдателя, который доступен в большинстве современных браузеров . Разработчики не обязаны делать что -либо дополнительное, чтобы включить это, но они могут отключить его при необходимости.

Предварительная загрузка важных изображений

Довольно часто элементы LCP - это изображения, а большие изображения могут задержать LCP. Это хорошая идея для предварительной загрузки критических изображений , чтобы браузер мог обнаружить это изображение раньше. При использовании элемента <img> подсказка для предварительной нагрузки может быть включена в HTML -головку следующим образом.

<link rel="preload" as="image" href="important.png">

Хорошо разработанный компонент изображения должен предложить способ настроить последовательность загрузки изображений, независимо от используемой структуры. В случае компонента изображения Next.js разработчики могут указать изображение, которое является хорошим кандидатом на предварительную нагрузку, используя priority атрибут компонента изображений.

<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />

Добавление priority атрибута упрощает разметку и удобнее использовать. Разработчики компонентов изображений также могут изучить параметры для применения эвристики для автоматизации предварительной загрузки для изображений выше, на странице, которые соответствуют конкретным критериям.

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

Изображение CDN рекомендуется для автоматизации оптимизации изображений, и они также поддерживают современные форматы изображений, такие как WebP и AVIF. Следующая компонент изображения Next.js по умолчанию использует CDN с использованием архитектуры загрузчика . В следующем примере показано, что загрузчик разрешает конфигурацию CDN в файле конфигурации next.js.

module.exports = {
  images: {
    loader: 'imgix',
    path: 'https://ImgApp/imgix.net',
  },
}

С помощью этой конфигурации разработчики могут использовать относительные URL -адреса в источнике изображения, а структура будет объединять относительный URL с путем CDN для создания абсолютного URL. Поддерживаются популярные изображения CDN, такие как Imgix , Cloudary и Akamai . Архитектура поддерживает использование пользовательского облачного провайдера путем реализации пользовательской функции loader для приложения.

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

Могут быть ситуации, когда веб -сайты не могут использовать изображения CDN. В таких случаях компонент изображения должен поддерживать самостоятельные изображения. Следующая компонент изображения Next.js использует оптимизатор изображения в качестве встроенного сервера изображений, который обеспечивает API, похожий на CDN. Оптимизатор использует Sharp для преобразования производственного изображения, если он установлен на сервере. Эта библиотека является хорошим выбором для тех, кто хочет создать свой собственный конвейер оптимизации изображений.

Поддержка прогрессивной загрузки

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

Следующая компонент изображения. Это можно использовать в качестве LQIP (низкокачественный заполнитель изображения) для отображения низкокачественного или размытого изображения, в то время как фактическое изображение загружается.

Влияние

Со всеми этими оптимизациями мы наблюдаем успех с компонентом изображения hearl.js в производстве, а также работаем с другими техническими стеками над аналогичными компонентами изображения.

Когда Leboncoin мигрировал свой Legacy JavaScript Frontend на next.js , они также обновили свой конвейер изображений, чтобы использовать компонент изображения healh.js. На странице, которая мигрировала с <img> на следующее/изображение, LCP снизился с 2,4 до 1,7. Общее изображение байты, загруженные для страницы, прошли с 663 КБ до 326 КБ (с ~ 100 КБ байтов с ленивым нагруженным изображением).

Извлеченные уроки

Любой, кто создает приложение Next.js, может извлечь выгоду из использования компонента изображения Next.js для оптимизации. Однако, если вы хотите создать аналогичные абстракции производительности для другой структуры или CMS, ниже приведены несколько уроков, которые мы извлекли по пути, которые могут быть полезными.

Предохранительные клапаны могут нанести больший вред, чем пользы

В раннем выпуске компонента изображения Next.js мы предоставили unsized атрибут, который позволил разработчикам обходить требования по размеру и использовать изображения с неопределенными измерениями. Мы думали, что это будет необходимо в тех случаях, когда было невозможно заранее узнать высоту или ширину изображения. Тем не менее, мы заметили, что пользователи рекомендовали unsized атрибут в вопросах GitHub в качестве решения всех проблем с требованиями размеров, даже в тех случаях, когда они могли решить проблему таким образом, чтобы не ухудшиться CLS. Впоследствии мы устарели и удалили unsized атрибут.

Отдельное полезное трение от бессмысленного раздражения

Требование по размеру изображения является примером «полезного трения». Он ограничивает использование компонента, но обеспечивает огромные преимущества производительности в обмене. Пользователи с готовностью примут ограничение, если у них есть четкое представление о потенциальных преимуществах производительности. Поэтому стоит объяснить этот компромисс в документации и другие опубликованные материалы о компоненте.

Тем не менее, вы можете найти обходные пути для такого трения, не жертвуя производительностью. Например, во время разработки компонента Image Next.js мы получили жалобы на то, что это раздражало искать размеры для локально хранимых изображений. Мы добавили статический импорт изображений , который оптимизирует этот процесс, автоматически извлекая размеры для локальных изображений во время сборки с помощью плагина Babel.

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

Если ваш компонент изображения не делает ничего, кроме как навязывать «полезное трение» на своих пользователей, разработчики, как правило, не захотят его использовать. Мы обнаружили, что, хотя функции производительности, такие как размер изображения и автоматическая генерация значений srcset , были наиболее важными. Удобные функции разработчиков, такие как автоматическая ленивая загрузка и встроенные размытые заполнители, также вызвали интерес к компоненту изображения healh.js.

Установите дорожную карту для функций для управления принятием

Создание решения, которое отлично подходит для всех ситуаций, очень сложно. Может быть заманчиво спроектировать что -то, что хорошо работает для 75% людей, а затем сказать другим 25%, что «В этих случаях этот компонент не для вас».

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

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

Заключение

Использование изображения и оптимизация сложны. Разработчики должны найти баланс между производительностью и качеством изображений, обеспечивая отличный пользовательский опыт. Это делает оптимизацию изображения дорогостоящим, высокоэффективным усилием.

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

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

,

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

Лина Сохони
Leena Sohoni
Кара Эриксон
Kara Erickson
Алекс Касл
Alex Castle

Изображения являются общим источником узких мест производительности для веб -приложений и ключевой фокусировкой для оптимизации. Неоптимизированные изображения вносят вклад в раздувание страницы и составляют более 70% от общего веса страниц в байтах на 90 процентиле. Несколько способов оптимизации изображений вызывают интеллектуальный «компонент изображения» с помощью производительности, запеченных в качестве по умолчанию.

Команда Aurora работала с Next.js , чтобы построить один такой компонент . Цель состояла в том, чтобы создать оптимизированный шаблон изображения, который веб -разработчики могут дополнительно настроить. Компонент служит хорошей моделью и устанавливает стандарт для создания компонентов изображения в других структурах, системах управления контентом (CMS) и технологий. Мы сотрудничали в аналогичном компоненте для nuxt.js, и мы работаем с угловой оптимизацией изображений в будущих версиях. В этом посте обсуждается, как мы разработали компонент следующего.js изображения и уроки, которые мы извлекли по пути.

Компонент изображения как расширение изображений

Проблемы и возможности оптимизации изображений

Изображения не только влияют на производительность, но и на бизнес. Количество изображений на странице было вторым величайшим предиктором конверсий пользователей, посещающих веб -сайты. Сессии, в которых конвертировались пользователи, имели на 38% меньше изображений, чем сеансы, где они не конвертировали. Lighthouse перечисляет множество возможностей для оптимизации изображений и улучшения жизненно важных веществ в рамках его аудита. Некоторые из общих областей, где изображения могут влиять на основные веб -жизненные силы, а пользовательский опыт заключается в следующем.

Unsized изображения повредят CLS

Изображения, подаваемые без указанного размера, могут вызвать нестабильность макета и внести свой вклад в высокий совокупный сдвиг макета ( CLS ). Установка атрибутов width и height на элементах <img> может помочь предотвратить смены макета. Например:

<img src="flower.jpg" width="360" height="240">

Ширина и высота должны быть установлены так, чтобы соотношение сторон визуализированного изображения близко к его естественному соотношению сторон. Значительная разница в соотношении сторон может привести к искажению изображения. Относительно новое свойство, которое позволяет вам указать, что аспект в CSS может помочь в размерах изображений ответственно при предотвращении CLS.

Большие изображения могут повредить LCP

Чем больше размер файла изображения, тем дольше потребуется для загрузки. Большое изображение может быть изображением «героя» для страницы или наиболее значимым элементом в сборе просмотра, ответственного за запуск самой большой довольной краски ( LCP ). Изображение, которое является частью критического контента и занимает много времени для загрузки, задержит LCP.

Во многих случаях разработчики могут уменьшить размеры изображений за счет лучшего сжатия и использования адаптивных изображений. Атрибуты srcset и sizes Attributes of element element справляются <img> для предоставления файлов изображений с разными размерами. Затем браузер может выбрать правильный в зависимости от размера экрана и разрешения.

Плохое сжатие изображения может повредить LCP

Современные форматы изображений, такие как AVIF или WebP, могут обеспечить лучшее сжатие, чем обычно используемые форматы JPEG и PNG. Лучшее сжатие уменьшает размер файла на 25-50% в некоторых случаях для того же качества изображения. Это сокращение приводит к более быстрому загрузке с меньшим потреблением данных. Приложение должно служить современным форматам изображений в браузеры, которые поддерживают эти форматы.

Загрузка ненужных изображений болит LCP

Изображения ниже сгиба или нет в точке зрения не отображаются пользователю при загрузке страницы. Они могут быть отложены, чтобы они не способствовали LCP и задерживали его. Ленивая загрузка может быть использована для загрузки таких изображений позже, когда пользователь прокручивается к ним.

Проблемы оптимизации

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

  • Приоритеты : веб -разработчики обычно склонны фокусироваться на коде, JavaScript и оптимизации данных. Таким образом, они могут не знать о проблемах с изображениями или о том, как их оптимизировать. Изображения, созданные дизайнерами или загруженные пользователями, могут не быть высокими в списке приоритетов.
  • Из-за коробки решения : даже если разработчики знают о нюансах оптимизации изображений, отсутствие все в одном из ящиков для их структуры или технологического стека может быть сдерживающим фактором.
  • Динамические изображения : в дополнение к статическим изображениям, которые являются частью приложения, динамические изображения загружаются пользователями или получены из внешних баз данных или CMS. Может быть сложно определить размер таких изображений, где источник изображения является динамичным.
  • Перегрузка разметки : решения для включения размера изображения или srcset для разных размеров требуют дополнительной разметки для каждого изображения, которые могут быть утомительными. Атрибут srcset был введен в 2014 году, но сегодня используется только 26,5% веб -сайтов. При использовании srcset разработчики должны создавать изображения в разных размерах. Такие инструменты, как Just-Gimme-An-Img, могут помочь, но должны использоваться вручную для каждого изображения.
  • Поддержка браузера : современные форматы изображений, такие как Avif и Webp, создают меньшие файлы изображений, но нуждаются в специальной обработке в браузерах, которые не поддерживают их. Разработчики должны использовать такие стратегии, как переговоры о контенте или элемент <picture чтобы изображения обслуживались всем браузерам.
  • Ленивые сложности для загрузки : существует несколько методов и библиотек, доступных для реализации ленивой загрузки для изображений ниже размера. Выбор лучшего может быть проблемой. Разработчики также могут не знать наилучшее расстояние от «сгиба» для загрузки отложенных изображений. Различные размеры просмотра на устройствах могут еще больше усложнить это.
  • Изменение ландшафта . Поскольку браузеры начинают поддерживать новые функции HTML или CSS для повышения производительности, разработчикам может быть трудно оценить каждый из них. Например, Chrome представляет функцию приоритета извлечения в качестве исследования происхождения . Его можно использовать для повышения приоритета конкретных изображений на странице. В целом, разработчикам будет проще, если бы такие улучшения были оценены и реализованы на уровне компонентов.

Компонент изображения в качестве решения

Возможности, доступные для оптимизации изображений, и задач в реализации их индивидуально для каждого приложения, привели нас к идее компонента изображения. Компонент изображения может инкапсулировать и обеспечивать лучшие практики. Заменив элемент <img> компонентом изображения, разработчики могут лучше решать свои проблемы с производительностью изображения.

За последний год мы работали с Framework Next.js для разработки и реализации их компонента изображения . Он может быть использован в качестве замены для существующих элементов <img> в приложениях next.js следующим образом.

// Before with <img> element:
function Logo() {
  return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}

// After with image component:
import Image from 'next/image'

function Logo() {
  return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}

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

Защита от смены макета

Как обсуждалось ранее, неостановленные изображения вызывают сдвиги макета и способствуют CLS. При использовании компонента изображения Next.js разработчики должны предоставить размер изображения, используя атрибуты width и height чтобы предотвратить любые сдвиги макета. Если размер неизвестен, разработчики должны указать layout=fill чтобы обслуживать необозначное изображение, которое находится в контейнере размера. В качестве альтернативы вы можете использовать статический импорт изображений, чтобы получить размер фактического изображения на жестком диске во время сборки и включить его в изображение.

// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />

// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />

// Image component with image import
import Image from 'next/image'
import logo from './logo.png'

function Logo() {
  return <Image src={logo} alt="logo" />
}

Поскольку разработчики не могут использовать компонент изображения Unszed, дизайн гарантирует, что они потребуют время, чтобы рассмотреть размер изображения и предотвратить сдвиги макета.

Облегчить отзывчивость

Чтобы сделать изображения, отвечающими на устройства, разработчики должны установить атрибуты srcset и sizes в элементе <img> . Мы хотели уменьшить эти усилия с помощью компонента изображения. We designed the Next.js Image component to set the attribute values only once per application. We apply them to all instances of the Image component based on the layout mode. We came up with a three-part solution:

  1. deviceSizes property: This property can be used to configure breakpoints one-time based on the devices common to the application user base. The default values for breakpoints are included in the config file.
  2. imageSizes property: This is also a configurable property used to get the image sizes corresponding to device size breakpoints.
  3. layout attribute in each image: This is used to indicate how to use the deviceSizes and imageSizes properties for each image. The supported values for layout mode are fixed , fill , intrinsic and responsive

When an image is requested with layout modes responsive or fill , Next.js identifies the image to be served based on the size of the device requesting the page and sets the srcset and sizes in the image appropriately.

The following comparison shows how the layout mode can be used to control the size of the image on different screens. We have used a demo image shared in the Next.js docs, viewed on a phone and a standard laptop.

Laptop screen Экран телефона
Layout = Intrinsic: Scales down to fit the container's width on smaller viewports. Does not scale up beyond the image's intrinsic size on a larger viewport. Container width is at 100%
Mountains image shown as isMountains image scaled down
Layout = Fixed: Image is not responsive. Width and height are fixed similar to ` ` element irrespective of the device where it is rendered.
Mountains image shown as isMountains image shown as is does not fit the screen
Layout = Responsive: Scale down or scale up depending on the width of the container on different viewports, maintaining aspect ratio.
Mountains image scaled up to fit the screenMountains image scaled down to fit the screen
Layout = Fill: Width and height stretched to fill the parent container. (Parent <div> width is set to 300*500 in this example)
Mountains image rendered to fit 300*500 sizeMountains image rendered to fit 300*500 size
Images rendered for different layouts

Provide built-in lazy-loading

The Image component provides a built-in, performant lazy loading solution as a default. When using the <img> element, there are a few options for lazy loading, but they all have drawbacks that make them tricky to use. A developer might adopt one of the following lazy loading approaches:

  • Specify the loading attribute: This is supported on all modern browsers .
  • Use the Intersection Observer API : Building a custom lazy-loading solution requires effort and a thoughtful design and implementation. Developers may not always have the time for this.
  • Import a third-party library to lazy-load images: Additional effort may be required to evaluate and integrate a suitable third-party library for lazy loading.

In the Next.js Image component, loading is set to "lazy" by default. Lazy loading is implemented using Intersection Observer, which is available on most modern browsers . Developers are not required to do anything extra to enable it, but they can disable it when needed.

Preload important images

Quite often, LCP elements are images, and large images can delay LCP. It is a good idea to preload critical images so the browser can discover that image sooner. When using an <img> element, a preload hint may be included in the HTML head as follows.

<link rel="preload" as="image" href="important.png">

A well-designed image component should offer a way to tweak the loading sequence of images, regardless of the framework used. In the case of the Next.js Image component, developers can indicate an image that is a good candidate for preload using the priority attribute of the images component.

<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />

Adding a priority attribute simplifies markup and is more convenient to use. Image component developers can also explore options to apply heuristics to automate preloading for above-the-fold images on the page that meet specific criteria.

Encourage high-performance image hosting

Image CDNs are recommended for automating image optimization, and they also support modern image formats like WebP and AVIF. The Next.js Image component uses an image CDN by default using a loader architecture . The following example shows that the loader allows for configuration of the CDN in the Next.js config file.

module.exports = {
  images: {
    loader: 'imgix',
    path: 'https://ImgApp/imgix.net',
  },
}

With this configuration, developers can use relative URLs in the image source, and the framework will concatenate the relative URL with the CDN path to generate the absolute URL. Popular image CDNs like Imgix , Cloudinary , and Akamai are supported. The architecture supports the use of a custom cloud provider by implementing a custom loader function for the app.

Support self-hosted images

There may be situations where websites cannot use image CDNs. In such cases, an image component must support self-hosted images. The Next.js Image component uses an image optimizer as a built-in image server that provides a CDN-like API. The optimizer uses Sharp for production image transformations if it is installed on the server. This library is a good choice for anyone looking to build their own image optimization pipeline.

Support progressive loading

Progressive loading is a technique used to hold users' interest by displaying a placeholder image usually of significantly lower quality while the actual image loads. It improves perceived performance and enhances the user experience. It can be used in combination with lazy loading for below-the-fold images or for above-the-fold images.

The Next.js Image component supports progressive loading for the image through the placeholder property. This can be used as an LQIP (Low-quality image placeholder) for displaying a low-quality or blurred image while the actual image loads.

Влияние

With all these optimizations incorporated, we have seen success with the Next.js Image component in production and are also working with other tech stacks on similar image components.

When Leboncoin migrated their legacy JavaScript frontend to Next.js , they also upgraded their image pipeline to use the Next.js Image component. On a page that migrated from <img> to next/image, LCP went down from 2.4s to 1.7s. The total image bytes downloaded for the page went from 663kB to 326kB (with ~100kB of lazy-loaded image bytes).

Извлеченные уроки

Anyone creating a Next.js app can benefit from using the Next.js Image component for optimization. However, if you want to build similar performance abstractions for another framework or CMS, the following are a few lessons we learned along the way that could be helpful.

Safety valves can cause more harm than good

In an early release of the Next.js Image component, we provided a unsized attribute that allowed developers to bypass the sizing requirement, and use images with unspecified dimensions. We thought this would be a necessary in instances where it was impossible to know the image's height or width in advance. However, we noticed users recommending the unsized attribute in GitHub issues as a catch-all solution to problems with the sizing requirement, even in cases where they could solve the problem in ways that didn't worsen CLS. We subsequently deprecated and removed the unsized attribute.

Separate useful friction from pointless annoyance

The requirement for sizing an image is an example of "useful friction." It restricts the use of the component, but it provides outsized performance benefits in exchange. Users will readily accept the constraint if they have a clear picture of the potential performance benefits. Therefore, it is worthwhile to explain this tradeoff in the documentation and other published material about the component.

However, you can find workarounds for such friction without sacrificing performance. For example, during the development of the Next.js Image component, we received complaints that it was annoying to look up sizes for locally stored images. We added static image imports , which streamline this process by automatically retrieving dimensions for local images at build time using a Babel plugin.

Strike a balance between convenience features and performance optimizations

If your image component does nothing but impose "useful friction" on its users, developers will tend to not want to use it. We found that although performance features like image sizing and automatic generation of srcset values were the most important. Developer-facing convenience features like automatic lazy loading and built-in blurry placeholders also drove interest in the Next.js Image component.

Set a roadmap for features to drive adoption

Building a solution that works perfectly for all situations is very difficult. It can be tempting to design something that works well for 75% of people and then tell the other 25% that "in these cases, this component isn't for you."

In practice, this strategy turns out to be at odds with your goals as a component designer. You want developers to adopt your component in order to benefit from its performance benefits. This is difficult to do if there is a contingent of users that are unable to migrate and feel left out of the conversation. They are likely to express disappointment, leading to negative perceptions that affect adoption.

It is advisable to have a roadmap for your component that covers all reasonable use cases over the long term. It also helps to be explicit in the documentation about what isn't supported and why in order to set expectations about the problems the component is intended to solve.

Заключение

Image usage and optimization is complicated. Developers have to find the balance between performance and quality of images while ensuring a great user experience. This makes image optimization a high-cost, high-impact endeavor.

Instead of having each app reinvent the wheel every time, we came up with a best practices template that developers, frameworks, and other tech-stacks could use as a reference for their own implementations. This experience will indeed prove valuable as we support other frameworks, on their image components.

The Next.js Image component has successfully improved performance outcomes in Next.js applications, thereby enhancing the user experience. We believe that it's a great model that would work well in the broader ecosystem, and we would love to hear from developers who would like to adopt this model in their projects.