Изображения
Изображения могут сильно влиять на производительность вашего приложения. Для достижения наилучших результатов их следует оптимизировать следующим образом:
- генерировать оптимальные форматы, такие как
.avifи.webp - создавать разные размеры для разных экранов
- обеспечивать эффективное кэширование ресурсов
Делать это вручную довольно утомительно. Существует множество подходов в зависимости от ваших задач и предпочтений.
Встроенная обработка в Vite
Заголовок раздела «Встроенная обработка в Vite»Vite автоматически обрабатывает импортируемые ресурсы для повышения производительности. Это касается и ресурсов, на которые ссылаются через функцию url() в CSS. К именам файлов добавляются хэши для возможности долгосрочного кэширования, а ресурсы меньше assetsInlineLimit встраиваются прямо в код. Обработка ресурсов в Vite чаще всего используется для изображений, но также полезна для видео, аудио и других типов файлов.
<script> import logo from '$lib/assets/logo.png';</script>
<img alt="Логотип проекта" src={logo} />@sveltejs/enhanced-img
Заголовок раздела «@sveltejs/enhanced-img»@sveltejs/enhanced-img — это плагин, построенный поверх встроенной обработки ресурсов в Vite. Он предоставляет готовое решение для обработки изображений: автоматически использует более эффективные форматы (avif и webp), устанавливает атрибуты width и height согласно естественным размерам изображения (чтобы предотвратить сдвиг макета), создаёт несколько вариантов размеров для разных устройств и удаляет EXIF-данные для повышения приватности. Плагин работает в любом проекте на базе Vite, включая (но не ограничиваясь) проекты SvelteKit.
Настройка
Заголовок раздела «Настройка»Установите:
npm i -D @sveltejs/enhanced-imgНастройте vite.config.js:
import { sveltekit } from '@sveltejs/kit/vite';import { enhancedImages } from '@sveltejs/enhanced-img';import { defineConfig } from 'vite';
export default defineConfig({ plugins: [ enhancedImages(), // должен идти перед плагином SvelteKit sveltekit() ]});Первая сборка займёт больше времени из-за высокой вычислительной стоимости преобразования изображений. Однако результат сборки будет кэшироваться в папке ./node_modules/.cache/imagetools, поэтому последующие сборки пройдут значительно быстрее.
Базовое использование
Заголовок раздела «Базовое использование»В компонентах .svelte используйте тег <enhanced:img> вместо <img> и указывайте путь к изображению через импорт ресурсов Vite:
<enhanced:img src="./path/to/your/image.jpg" alt="Описание" />Во время сборки ваш тег <enhanced:img> будет заменён на <img>, обёрнутый в <picture>, который предоставляет несколько форматов и размеров изображения. Уменьшать размер изображений можно без потери качества, поэтому следует предоставлять изображение с самым высоким разрешением, которое вам требуется — меньшие версии будут автоматически сгенерированы для различных типов устройств.
Рекомендуется предоставлять изображение в разрешении 2x для HiDPI-дисплеев (также известных как Retina-дисплеи). Компонент <enhanced:img> автоматически будет отдавать уменьшенные версии для устройств с меньшим разрешением.
Динамический выбор изображения
Заголовок раздела «Динамический выбор изображения»Вы также можете вручную импортировать ресурс изображения и передать его в <enhanced:img>. Это удобно, когда у вас есть коллекция статических изображений и вы хотите выбрать одно из них динамически или перебрать их. В этом случае нужно обновить как оператор import, так и элемент <img>, как показано ниже, чтобы указать, что их нужно обработать.
<script> import MyImage from './path/to/your/image.jpg?enhanced';</script>
<enhanced:img src={MyImage} alt="описание" />Вы также можете использовать import.meta.glob из Vite. Обратите внимание, что enhanced нужно указывать через пользовательский запрос:
<script> const imageModules = import.meta.glob( '/path/to/assets/*.{avif,AVIF,gif,GIF,heif,HEIF,jpeg,JPEG,jpg,JPG,png,PNG,tiff,TIFF,webp,WEBP}', { eager: true, query: { enhanced: true } } )</script>
{#each Object.entries(imageModules) as [_path, module]} <enhanced:img src={module.default} alt="описание" />{/each}Естественные размеры
Заголовок раздела «Естественные размеры»Атрибуты width и height являются необязательными, так как они могут быть автоматически определены из исходного изображения и будут добавлены при предобработке тега <enhanced:img>. Благодаря этим атрибутам браузер может зарезервировать нужное пространство заранее, предотвращая сдвиг макета.
Если вы хотите использовать другие значения width и height, вы можете задать их через CSS. Поскольку препроцессор автоматически добавляет width и height, чтобы один из размеров рассчитывался автоматически, вам нужно явно указать это:
<style> .hero-image img { width: var(--size); height: auto; }</style>srcset и sizes
Заголовок раздела «srcset и sizes»Если у вас большое изображение, например, hero-изображение, занимающее всю ширину дизайна, рекомендуется указать атрибут sizes. Это позволит запрашивать уменьшенные версии на устройствах с маленькими экранами. Например, для изображения шириной 1280px вы можете указать примерно следующее:
<enhanced:img src="./image.png" sizes="min(1280px, 100vw)"/>Если указан атрибут sizes, компонент <enhanced:img> будет генерировать уменьшенные изображения для устройств с маленькими экранами и автоматически заполнять атрибут srcset.
Самое маленькое изображение, которое генерируется автоматически, имеет ширину 540px. Если вам нужны ещё более мелкие версии или вы хотите задать собственные значения ширины, это можно сделать с помощью параметра запроса w:
<enhanced:img src="./image.png?w=1280;640;400" sizes="(min-width:1920px) 1280px, (min-width:1080px) 640px, (min-width:768px) 400px"/>Если атрибут sizes не указан, будут сгенерированы версия для HiDPI/Retina и версия стандартного разрешения. Изображение, которое вы предоставляете, должно иметь в 2 раза большее разрешение, чем то, которое вы планируете отображать. Это позволит браузеру корректно показывать его на устройствах с высоким соотношением пикселей устройства.
Трансформации для каждого изображения
Заголовок раздела «Трансформации для каждого изображения»По умолчанию enhanced-изображения преобразуются в более эффективные форматы. Однако при необходимости вы можете применить дополнительные трансформации: размытие, изменение качества, сжатие, поворот и другие. Для этого добавьте строку запроса к изображению:
<enhanced:img src="./path/to/your/image.jpg?blur=15" alt="Описание" />Полный список директив доступен в репозитории imagetools.
Динамическая загрузка изображений из CDN
Заголовок раздела «Динамическая загрузка изображений из CDN»В некоторых случаях изображения недоступны во время сборки — например, они могут храниться в системе управления контентом (CMS) или на бэкенде.
Использование сети доставки контента (CDN) позволяет оптимизировать такие изображения динамически и даёт больше гибкости в выборе размеров, но требует дополнительной настройки и может быть платным. В зависимости от стратегии кэширования браузер может не использовать кэшированную версию ресурса, пока не получит ответ 304 от CDN.
Работа с CDN позволяет использовать обычный тег <img>, так как CDN сам выбирает подходящий формат на основе заголовка User-Agent. В отличие от оптимизации во время сборки, которая генерирует тег <picture> с несколькими источниками. Кроме того, некоторые CDN генерируют изображения лениво, что может негативно сказаться на производительности сайтов с низким трафиком и часто меняющимися изображениями.
CDN можно использовать без каких-либо библиотек. Однако существует несколько библиотек с поддержкой Svelte, которые значительно упрощают работу. @unpic/svelte — это независимая от конкретного CDN библиотека, поддерживающая большое количество провайдеров. Также многие конкретные CDN, например Cloudinary, имеют официальную поддержку Svelte. Наконец, некоторые системы управления контентом с поддержкой Svelte (такие как Contentful, Storyblok и Contentstack) имеют встроенные средства работы с изображениями.
Лучшие практики
Заголовок раздела «Лучшие практики»- Для каждого типа изображений выбирайте подходящий из описанных выше подходов. Все три решения можно комбинировать в одном проекте. Например, использовать встроенную обработку Vite для изображений в
<meta>-тегах,@sveltejs/enhanced-imgдля изображений на главной странице и динамический подход для пользовательского контента. - Рассмотрите возможность раздачи всех изображений через CDN независимо от способа оптимизации. CDN уменьшают задержки, распространяя копии статических ресурсов по всему миру.
- Исходные изображения должны иметь хорошее качество и разрешение. Они должны быть в 2 раза шире, чем максимальный размер отображения, чтобы качественно обслуживать HiDPI-устройства. Обработка изображений может уменьшать их размер для экономии трафика на маленьких экранах, но увеличивать размер и «придумывать» пиксели — это пустая трата трафика.
- Для изображений, значительно превышающих ширину мобильного устройства (примерно 400 px), например hero-изображений на всю ширину страницы, обязательно указывайте атрибут
sizes, чтобы на маленьких экранах отдавались уменьшенные версии. - Для важных изображений, таких как изображение Largest Contentful Paint (LCP), устанавливайте
fetchpriority="high"и избегайтеloading="lazy", чтобы они загружались как можно раньше. - Задавайте изображению контейнер или стили, чтобы оно было ограничено по размеру и не «прыгало» во время загрузки страницы, влияя на Cumulative Layout Shift (CLS). Атрибуты
widthиheightпомогают браузеру зарезервировать место заранее, поэтому@sveltejs/enhanced-imgдобавляет их автоматически. - Всегда указывайте хорошее описание в атрибуте
alt. Компилятор Svelte будет предупреждать вас, если вы его пропустите. - Не используйте
emилиremв атрибутеsizesи не меняйте базовый размер этих единиц. Вsizesи медиа-запросахemиremвсегда соответствуют стандартномуfont-sizeпользователя. Например, объявлениеsizes="(min-width: 768px) min(100vw, 108rem), 64rem"может работать некорректно, если вы изменили размер шрифта в CSS (например,html { font-size: 62.5%; }). В таком случае пространство, зарезервированное браузером на этапе предзагрузки, будет отличаться от реального размера элемента.