Каждая лишняя секунда загрузки обходится дорого. Google ещё в 2017 году зафиксировал: при увеличении времени загрузки с 1 до 3 секунд вероятность того, что пользователь уйдёт, вырастает на 32%. При 5 секундах — уже на 90%. С тех пор люди стали только нетерпеливее.
Если у вас сайт грузится дольше 3 секунд — вы теряете клиентов. Не абстрактно, а буквально: они закрывают вкладку и идут к конкуренту.
Разберём, что реально влияет на скорость и что можно сделать без переписывания всего с нуля.
Сначала измерьте — потом оптимизируйте
Без замеров оптимизация — это стрельба вслепую. Два инструмента, которые нужны всегда:
Google PageSpeed Insights (pagespeed.web.dev) — показывает Core Web Vitals: LCP, CLS, INP. Это метрики, на которые смотрит Google при ранжировании. Бесплатно, работает онлайн, ничего устанавливать не надо.
WebPageTest (webpagetest.org) — более детальный анализ. Показывает водопад запросов (waterfall), время до первого байта (TTFB), можно эмулировать разные регионы и типы соединений.
Что смотреть в первую очередь:
- LCP (Largest Contentful Paint) — когда загружается главный контент страницы. Норма: до 2,5 секунды.
- TTFB (Time to First Byte) — как быстро сервер отвечает. Норма: до 800 мс. Если больше — проблема на уровне сервера или хостинга.
- Размер страницы — сколько весит всё, что скачивает браузер. Средний сайт в 2026 году весит около 2,5 МБ. Это много.
После замера будет понятно, где узкое место: картинки, JS, сервер или что-то ещё.
Изображения — главный пожиратель скорости
В большинстве случаев именно картинки составляют 60–80% веса страницы. Здесь самый быстрый выигрыш.
Используйте современные форматы. WebP весит в среднем на 25–35% меньше JPEG при том же качестве. AVIF — ещё на 20% легче WebP, но поддерживается не всеми браузерами. Безопасная стратегия — отдавать WebP с фолбэком на JPEG через тег <picture>:
<picture>
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" alt="Описание">
</picture>
Сжимайте изображения перед загрузкой. Squoosh (squoosh.app) — бесплатный инструмент от Google прямо в браузере. Можно сжать фото с 800 КБ до 120 КБ без заметной потери качества. Для автоматизации на сервере — ImageMagick или Sharp (Node.js).
Используйте атрибут loading="lazy". Браузер загрузит изображения только когда они появятся в зоне видимости. Одна строка кода, работает во всех современных браузерах:
<img src="photo.jpg" loading="lazy" alt="Описание">
Задавайте размеры изображений. Если не указать width и height, браузер не знает, сколько места зарезервировать, и страница «прыгает» при загрузке (это влияет на CLS). Всегда прописывайте размеры явно.
Не загружайте изображения больше, чем нужно. Если на мобильном экране картинка отображается в 400px, незачем грузить 1600px. Используйте атрибут srcset:
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w"
sizes="(max-width: 600px) 400px, 800px"
alt="Описание"
>
Кэширование — чтобы не грузить одно и то же дважды
Когда пользователь заходит на сайт повторно, браузер может взять файлы из кэша, а не скачивать снова. Настраивается через HTTP-заголовки на сервере.
Для статичных файлов (CSS, JS, картинки) ставьте долгий кэш — год и более. Для HTML — короткий или вообще без кэша, чтобы обновления сразу доходили до пользователей.
Пример для Nginx:
location ~* \.(jpg|jpeg|png|gif|webp|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
immutable говорит браузеру: «этот файл никогда не изменится, не проверяй его даже при принудительном обновлении». Это работает только если вы используете хэши в именах файлов (например, main.a3f9c2.js) — стандартная практика при сборке через Webpack, Vite, Parcel.
Кэширование на сервере. Если сайт на WordPress или другой CMS — подключите серверное кэширование. WP Super Cache или W3 Total Cache генерируют статичные HTML-файлы вместо того, чтобы каждый раз запрашивать базу данных. На высоконагруженных сайтах это снижает TTFB с 500–800 мс до 50–100 мс.
Минификация и сжатие кода
Минификация — удаление пробелов, комментариев, переименование переменных. CSS с 150 КБ после минификации может стать 90 КБ. Для JS экономия ещё больше. Если используете сборщик (Vite, Webpack) — минификация включается одной строкой в конфиге. В WordPress — плагины Autoptimize или LiteSpeed Cache.
Gzip и Brotli — сжатие на уровне передачи данных. Сервер сжимает файл перед отправкой, браузер распаковывает. Brotli эффективнее Gzip примерно на 15–25%. Включается в Nginx:
gzip on;
gzip_types text/css application/javascript application/json;
brotli on;
brotli_types text/css application/javascript application/json;
Проверить, работает ли сжатие: в DevTools на вкладке Network смотрите колонки Size и Transferred. Если Transferred значительно меньше Size — сжатие работает.
Оптимизация JavaScript — самое больное место
JS блокирует рендеринг страницы. Пока скрипт не загрузился и не выполнился, браузер не отрисует то, что идёт после него.
Атрибуты async и defer. По умолчанию скрипт в <head> останавливает парсинг HTML. async загружает скрипт параллельно и выполняет сразу после загрузки. defer — загружает параллельно, но выполняет только после парсинга всего HTML. Для большинства скриптов подходит defer:
<script src="analytics.js" defer></script>
Code splitting. Не грузите весь JS сразу. Код, который нужен только на странице корзины, не нужен на главной. Webpack и Vite поддерживают динамический импорт из коробки:
// Грузим модуль только когда он нужен
const { initCart } = await import('./cart.js');
Tree shaking. Если подключаете библиотеку типа Lodash ради одной функции — подключайте только её, а не всю библиотеку:
// Плохо — загружается весь Lodash (~70 КБ)
import _ from 'lodash';
// Хорошо — только нужная функция (~1 КБ)
import debounce from 'lodash/debounce';
Проверьте, что вы вообще грузите. Инструмент bundlephobia.com показывает вес любой npm-пакета. Иногда оказывается, что ради небольшой задачи подключена библиотека на 200 КБ, а нативный JS справился бы тремя строками.
CDN — когда сервер далеко от пользователя
CDN (Content Delivery Network) — сеть серверов по всему миру. Пользователь из Владивостока получает файлы не с сервера в Москве, а с ближайшей точки CDN — например, из Хабаровска. Скорость передачи данных физически ограничена расстоянием.
Cloudflare — самый распространённый вариант, есть бесплатный тариф. Помимо CDN даёт защиту от DDoS и автоматическую минификацию. Подключается на уровне DNS — менять хостинг не нужно.
Для статичных файлов (картинки, видео, шрифты) CDN особенно эффективен. Динамический контент — сложнее, но тоже решаемо.
Шрифты — незаметный, но важный фактор
Кастомные шрифты могут существенно тормозить отображение текста.
Используйте font-display: swap. По умолчанию браузер ждёт загрузки шрифта перед отображением текста (FOIT — Flash of Invisible Text). swap говорит: покажи системный шрифт сразу, потом замени на кастомный:
@font-face {
font-family: 'MyFont';
src: url('font.woff2') format('woff2');
font-display: swap;
}
Загружайте только нужные начертания. Если используете только Regular и Bold — не подключайте Light, Medium, SemiBold, Black. Каждое начертание — отдельный файл.
Используйте формат WOFF2. Он весит на 30% меньше WOFF и поддерживается всеми современными браузерами.
Если используете Google Fonts — размещайте шрифты на своём сервере. Внешний запрос к fonts.googleapis.com — это лишний DNS-lookup и время ожидания. Инструмент google-webfonts-helper помогает скачать нужные шрифты.
Критический CSS и предзагрузка ресурсов
Critical CSS — инлайнинг стилей, необходимых для отображения верхней части страницы (above the fold), прямо в HTML. Браузер не ждёт загрузки CSS-файла и сразу рисует контент. Остальные стили подгружаются асинхронно. Инструмент Critical (npm) автоматизирует этот процесс.
Preload для критичных ресурсов. Если знаете, что определённый ресурс точно понадобится — сообщите браузеру заранее:
<link rel="preload" href="hero.webp" as="image">
<link rel="preload" href="main.woff2" as="font" type="font/woff2" crossorigin>
DNS prefetch и preconnect для внешних ресурсов:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://analytics.example.com">
База данных и серверная часть
Если TTFB высокий (больше 800 мс) — проблема не в клиентской части. Смотрите на сервер.
Индексы в базе данных. Медленные запросы без индексов — частая причина тормозов. В MySQL/PostgreSQL используйте EXPLAIN для анализа запросов. Добавление индекса на нужное поле может ускорить запрос с 2 секунд до 10 миллисекунд.
OPcache для PHP. Кэширует скомпилированные PHP-скрипты в памяти. Включается одной строкой в php.ini и ускоряет работу PHP-приложений в 5–10 раз.
Redis или Memcached для кэша. Результаты тяжёлых запросов к БД сохраняйте в памяти. Повторный запрос отдаёт данные за микросекунды вместо десятков миллисекунд.
Проверьте сторонние скрипты
Аналитика, чаты, пиксели соцсетей, виджеты — каждый сторонний скрипт делает отдельный запрос к внешнему серверу и выполняет свой JS. На некоторых сайтах сторонние скрипты составляют половину веса страницы.
Проверьте в WebPageTest, какие домены запрашиваются при загрузке. Уберите всё лишнее. Оставшееся — загружайте с async или defer, чтобы не блокировать основной поток.
Если используете Google Analytics 4 — можно настроить серверную аналитику, чтобы не грузить JS на клиенте вообще.
Что делать дальше
Оптимизация скорости — не разовая задача. Сайт обрастает новыми скриптами, плагинами, тяжёлыми картинками. Имеет смысл проверять PageSpeed раз в квартал.
Порядок действий, если хотите начать прямо сейчас:
- Запустите PageSpeed Insights и посмотрите, что именно тормозит.
- Переведите картинки в WebP, поставьте
loading="lazy".
- Включите Gzip/Brotli и кэширование на сервере.
- Подключите Cloudflare (бесплатно).
- Уберите неиспользуемые сторонние скрипты.
Эти пять шагов в большинстве случаев дают ощутимый результат без переписывания кода.
Если сайт исторически нагроможден — иногда проще сделать его заново, чем чинить. В REEXY корпоративный сайт начинается от 15 000 ₽, и в эту стоимость уже входит оптимизация под Core Web Vitals. Быстрый сайт с нуля часто обходится дешевле, чем долгая реанимация старого.