Урок 49. Примеры: Оптимизация и производительность

📁 Раздел: Качество вёрстки ⏱️ Время изучения: ~85 мин 🎯 Сложность: Продвинутая
#loading #picture #font-display #will-change

⚡ Кратко

Ниже — приёмы оптимизации. Где есть видимый результат (анимация, движение) — он показан в превью. Где приём «невидимый» (lazy-load, форматы, minify) — показан код и пояснён эффект схемой.

Рабочие примеры

Тема про производительность — результат часто не визуальный. Поэтому: где есть движение, смотри превью; где приём про загрузку — смотри код и схему «эффекта».

1. Дёшево vs дорого: анимируем transform, а не top

Оба блока двигаются вверх при наведении. Слева — через transform (composite, GPU, без reflow), справа — через top (reflow на каждом кадре). Визуально похоже, по нагрузке — нет. Наведи мышь.

✅ transform: translateY(-8px)
дёшево — только composite
⚠️ top: -8px
дорого — reflow на каждом кадре
/* ✅ дёшево: GPU, без пересчёта раскладки */
.card:hover { transform: translateY(-8px); }

/* ⚠️ дорого: каждый кадр запускает reflow */
.card-bad:hover { top: -8px; }

2. Ленивая загрузка изображений (loading="lazy")

Атрибут loading="lazy" откладывает загрузку картинок ниже первого экрана до момента, когда пользователь до них доскроллит. Эффект невидим глазу, но первый экран грузится быстрее. Обязательно указывай width и height — это резервирует место и убирает скачок вёрстки (CLS).

Первый экран грузится сразу ✅ Ниже сгиба грузится при скролле loading="lazy" ⏳
Браузер не качает то, что пользователь ещё не увидел.
<!-- картинка первого экрана: грузим сразу -->
<img src="hero.webp" width="1200" height="600" alt="...">

<!-- картинки ниже: откладываем -->
<img src="gallery-1.webp" width="600" height="400"
     loading="lazy" alt="...">

3. Современные форматы изображений (WebP/AVIF)

Один и тот же снимок в WebP/AVIF весит в разы меньше, чем JPEG/PNG при том же качестве (связь с уроком 36). Тег <picture> отдаёт лучший формат, который поддерживает браузер, с откатом на старый. Результат тот же для глаза — но меньше байтов по сети.

PNG ~320 КБ
JPEG ~140 КБ
WebP ~70 КБ
AVIF ~45 КБ
<picture>
  <source srcset="photo.avif" type="image/avif">
  <source srcset="photo.webp" type="image/webp">
  <img src="photo.jpg" width="600" height="400" alt="...">
</picture>
⚠️ Проверить по документации: конкретные размеры файлов зависят от изображения и настроек кодека — цифры на схеме иллюстративны. Сравнивайте свои файлы через Squoosh/imagemin.

4. font-display: swap — текст виден сразу

По умолчанию браузер прячет текст, пока грузится кастомный шрифт («невидимый текст», FOIT). font-display: swap сразу показывает текст системным шрифтом, а потом подменяет на нужный. Контент читаем мгновенно.

Без swap (FOIT)
текст пустой, пока грузится шрифт
С swap
Текст виден сразу
потом плавно подменится шрифт
@font-face {
  font-family: "Inter";
  src: url("inter.woff2") format("woff2");
  font-display: swap;   /* текст виден сразу */
}

5. Critical CSS + минификация

Минифицированный CSS — тот же код без пробелов и переносов: для браузера одинаков, но весит меньше. Critical CSS первого экрана встраивают прямо в <head>, остальное грузят отдельным файлом. Так первый экран рисуется, не дожидаясь всей таблицы стилей.

.hero{padding:2rem}.card{gap:1rem} ← 1 строка, меньше байтов
style.css 48 КБ
style.min.css 31 КБ
<head>
  <!-- критический CSS первого экрана — инлайн -->
  <style>.hero{padding:2rem}.card{gap:1rem}</style>
  <!-- остальное грузим отдельно и не блокируем рендер -->
  <link rel="stylesheet" href="style.min.css">
</head>
Эксперимент: открой DevTools → вкладка Network, перезагрузи страницу с «Slow 3G» и посмотри, какие ресурсы блокируют первый экран. Затем DevTools → Lighthouse → запусти аудит Performance.

Навигация