Урок 02

Изображения: оптимизация, 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.