Изображения: оптимизация, lazy-load, responsive
Зачем оптимизировать
Проблемы:
- Вес — картинки 70% трафика.
- Время загрузки — LCP.
- Трафик — особенно на мобильных.
- SEO — Core Web Vitals.
Что даёт оптимизация:
- Быстрее.
- Дешевле.
- Лучше в поиске.
- Меньше отказов.
Форматы
Растровые:
- JPEG — фото, без прозрачности.
- PNG — прозрачность, скриншоты.
- WebP — современный, меньше на 25-35%.
- AVIF — новее, ещё меньше.
- GIF — анимации, устаревает.
Векторные:
- SVG — иконки, лого, графики.
Правило:
- Фото — AVIF с WebP и JPEG fallback.
- Иконки и лого — SVG.
- Скриншоты с текстом — PNG.
Выбор формата
| Тип | Формат |
|---|---|
| Фото | AVIF / WebP / JPEG |
| Иконка | SVG |
| Логотип | SVG |
| Скриншот | PNG / WebP |
| Анимация | MP4 (не GIF) |
| Прозрачность | PNG / WebP / AVIF |
<picture>
Разные форматы с fallback:
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Описание" width="800" height="600">
</picture>
Что происходит:
- Браузер с AVIF → AVIF.
- WebP → WebP.
- Старый → JPEG.
Правило: AVIF → WebP → JPEG.
srcset
Разные разрешения:
<img
src="image-800.jpg"
srcset="
image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w,
image-1600.jpg 1600w
"
sizes="
(max-width: 600px) 100vw,
(max-width: 1024px) 50vw,
800px
"
alt="Описание"
width="800"
height="600"
>
Что происходит: браузер выбирает подходящий размер по ширине экрана.
Что даёт:
- Не грузит 1600px на мобильном.
- Загружает 1600px на retina-десктопе.
sizes — что означает
sizes="
(max-width: 600px) 100vw, /* на маленьких — 100% ширины */
(max-width: 1024px) 50vw, /* на средних — 50% */
800px /* на больших — фикс 800px */
"
Правило: sizes описывает, какой ширины картинка будет на разных экранах.
Lazy loading
Атрибут:
<img src="image.jpg" alt="..." loading="lazy">
Что даёт: картинка грузится, когда близко к viewport.
Правило:
loading="lazy"— для картинок ниже первого экрана.loading="eager"(или без атрибута) — для hero и лого.- Не ставить lazy на первую картинку.
⚠️ Lazy на LCP-картинке ухудшает метрику.
decoding
<img src="image.jpg" alt="..." decoding="async">
Что даёт: не блокирует рендер при декодировании.
Значения:
sync— синхронно.async— асинхронно.auto— браузер решает.
Правило: decoding="async" — для большинства.
Width и height
Обязательно:
<img src="image.jpg" alt="..." width="800" height="600">
Что даёт: резервирует место, нет layout shift (CLS).
CSS:
img {
max-width: 100%;
height: auto;
}
Правило: всегда указывать width и height.
Aspect-ratio
Для карточек:
.card__image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
Что даёт:
- Фиксированные пропорции.
- Без CLS.
- Обрезка без искажений.
object-fit
img {
object-fit: cover; /* обрезать, сохранив пропорции */
object-fit: contain; /* вписать целиком */
object-fit: fill; /* растянуть */
object-fit: none; /* оригинал */
object-fit: scale-down; /* минимальный из none/contain */
}
Правило:
cover— превью карточек.contain— логотипы, схемы.
object-position
img {
object-fit: cover;
object-position: center top; /* фокус на верх */
}
Когда: если центр объекта не там, где нужно.
Оптимизация через инструменты
Онлайн:
- TinyPNG — PNG, JPEG.
- Squoosh — все форматы.
- SVGOMG — SVG.
CLI:
# sharp-cli
npx sharp-cli -i input.jpg -o output.avif
# cwebp
cwebp -q 80 input.jpg -o output.webp
# avifenc
avifenc -q 60 input.jpg output.avif
В сборке (Vite, Next):
- Автоматическая оптимизация.
- Ресайз под нужные размеры.
- Современные форматы.
Правило 100 KB
Ориентир:
- Hero — до 200 KB.
- Карточка — до 100 KB.
- Иконка — до 5 KB.
- Аватар — до 30 KB.
Правило: если больше — оптимизировать.
CDN для изображений
Что даёт:
- Оптимизация на лету.
- Ресайз по параметрам URL.
- Автоматический WebP/AVIF.
Примеры: Cloudinary, imgix, Cloudflare Images.
URL:
https://cdn.example.com/image.jpg?w=800&fm=auto&q=80
Практический пример
Hero с адаптивом:
<picture>
<source
media="(max-width: 600px)"
srcset="hero-600.avif"
type="image/avif"
>
<source
media="(max-width: 600px)"
srcset="hero-600.webp"
type="image/webp"
>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img
src="hero.jpg"
alt="Курсы для разработчиков"
width="1200"
height="600"
fetchpriority="high"
>
</picture>
fetchpriority="high" — для LCP.
Аватар:
<img
src="avatar.webp"
alt="Иван"
width="64"
height="64"
loading="lazy"
decoding="async"
class="rounded-circle"
>
<figcaption>
<figure>
<img
src="image.webp"
alt="Схема архитектуры"
width="800"
height="600"
loading="lazy"
>
<figcaption>Рис. 1. Архитектура приложения</figcaption>
</figure>
Практика
1. Конвертируйте JPEG в WebP:
cwebp -q 80 photo.jpg -o photo.webp
2. Сравните размеры.
3. Добавьте <picture> с AVIF/WebP/JPEG.
4. Настройте srcset для hero.
5. Проверьте loading="lazy" для картинок ниже экрана.
6. Убедитесь, что у всех картинок есть width и height.
7. Прогоните Lighthouse → Performance — метрики LCP и CLS.
Частые ошибки
1. Нет width и height:
Layout shift при загрузке
Решение: указать.
2. Lazy на первой картинке:
LCP ухудшается
Решение: fetchpriority="high" без lazy.
3. GIF для видео:
10 MB GIF
Решение: MP4 с <video autoplay loop muted>.
4. PNG для фото:
В 3 раза больше JPEG
Решение: WebP/AVIF/JPEG.
5. Одна большая картинка для всех:
1600px на мобильном
Решение: srcset + sizes.
6. Без alt:
Не для скринридеров и SEO
Решение: всегда alt.
7. Битые картинки без fallback:
Пустое место
Решение: alt-текст как fallback.
8. Оптимизация только вручную:
Забыли одну картинку
Решение: автоматизация в сборке.
Итог
- Форматы: AVIF, WebP, JPEG, SVG.
<picture>— для fallback.srcset+sizes— адаптив.loading="lazy"— ниже экрана.fetchpriority="high"— для LCP.width+height— против CLS.aspect-ratio— фиксированные пропорции.object-fit: cover— обрезка.- До 100 KB — ориентир.
- Автоматизация в сборке.
- CDN — для больших проектов.
Дальше — оптимизация CSS: Autoprefixer, PostCSS, критический CSS.