Загрузка и производительность

Несколько атрибутов и тегов в head решают, загрузится страница за секунду или будет «висеть»: defer у скриптов, preload у шрифтов, lazy у картинок.

Производительность загрузки — то, как быстро страница становится видимой и интерактивной. На неё напрямую влияют способ подключения скриптов и ресурсов в head и атрибуты загрузки картинок.

Скорость — это не только удобство, но и фактор ранжирования: поисковики учитывают, как быстро страница отображается и реагирует на действия. Самая частая беда — блокирующий скрипт в head: пока браузер качает и исполняет файл <script>, он останавливает построение страницы, и пользователь видит белый экран. Лечится это правильными атрибутами и подсказками браузеру, какие ресурсы важны. Разберём инструменты, которые дают наибольший выигрыш малой кровью.

Зачем это на практике

Представьте лендинг с тремя скриптами аналитики в head без всяких атрибутов. Браузер дойдёт до первого <script>, остановит разбор HTML, скачает и выполнит его, потом второй, третий — и только потом нарисует контент. Пользователь несколько секунд смотрит в пустоту. Добавьте к каждому скрипту defer — и страница рисуется сразу, а скрипты подгрузятся в фоне. Тот же контент, но ощущение мгновенной загрузки. Производительность — это во многом грамотная расстановка таких подсказок.

defer и async у скриптов

По умолчанию <script src="..."> блокирует разбор HTML. Два атрибута это меняют:

<script src="analytics.js" defer></script>
<script src="widget.js" async></script>
  • defer — скрипт качается параллельно с разбором страницы и выполняется ПОСЛЕ её построения, в порядке подключения. Идеален для скриптов, которым нужен готовый DOM.
  • async — скрипт тоже качается параллельно, но выполняется СРАЗУ как скачался, не дожидаясь страницы и без гарантии порядка. Подходит для независимых счётчиков.

Правило простое: для большинства своих скриптов берите defer — он не блокирует отрисовку и сохраняет порядок выполнения. async оставляйте для полностью независимых сторонних виджетов, которым всё равно, готов ли DOM и в каком порядке они стартуют.

preload, prefetch, preconnect

Это «подсказки ресурсов» (resource hints) — они говорят браузеру заранее позаботиться о том, что понадобится:

<link rel="preconnect" href="https://fonts.example.com">
<link rel="preload" href="/fonts/main.woff2" as="font" crossorigin>
<link rel="prefetch" href="/next-page.html">
  • preconnect — заранее установить соединение с чужим доменом (DNS + TLS), чтобы потом не терять время на рукопожатие. Полезно для шрифтов и CDN.
  • preload — высокоприоритетно скачать ресурс, нужный на ТЕКУЩЕЙ странице (например, шрифт или ключевую картинку), пока браузер ещё разбирает HTML. Атрибут as обязателен — он задаёт тип.
  • prefetch — низкоприоритетно подтянуть ресурс, который, вероятно, понадобится на СЛЕДУЮЩЕЙ странице. Делается в фоне, на будущее.

Главное — не злоупотреблять: если «предзагрузить» всё подряд, вы отнимете канал у действительно важного и сделаете только хуже. Preload — для одного-двух критичных ресурсов.

favicon и манифест PWA

Иконку вкладки браузер ищет в head (или по умолчанию /favicon.ico):

<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="manifest" href="/site.webmanifest">

Тег <link rel="manifest"> подключает веб-манифест — JSON-файл с именем приложения, иконками и цветами. Он превращает сайт в устанавливаемое PWA: пользователь может «добавить на главный экран», и сайт откроется как приложение, с иконкой и без адресной строки. Манифест сам по себе невелик, но именно он, вместе со service worker, делает из обычной страницы устанавливаемое приложение.

lazy-loading картинок

Картинки внизу длинной страницы не нужны, пока пользователь до них не доскроллит. Атрибут loading="lazy" откладывает их загрузку до момента приближения к экрану:

<img src="photo.jpg" loading="lazy" width="800" height="600" alt="Описание">

Это экономит трафик и ускоряет первую отрисовку: браузер не тратит канал на изображения, которые ещё не видны. Важная деталь — задавайте width и height (или CSS-размер): иначе при подгрузке картинки страница «прыгает», смещая контент. А вот для главной картинки в самом верху loading="lazy" ставить НЕ нужно — её, наоборот, хочется показать как можно раньше.

Шпаргалка

ИнструментКогда применять
deferсвои скрипты, которым нужен готовый DOM
asyncнезависимые сторонние счётчики
preconnectранний коннект к шрифтам/CDN
preload1–2 критичных ресурса текущей страницы
prefetchресурс вероятной следующей страницы
loading="lazy"картинки ниже первого экрана

Как это работает под капотом

Браузер строит страницу в два потока: парсер собирает DOM из HTML, а параллельный «сканер предзагрузки» забегает вперёд и заранее качает обнаруженные ресурсы. Обычный <script> ломает эту параллельность: парсер обязан остановиться, дождаться скачивания и выполнения скрипта, и лишь потом продолжить — отсюда белый экран. defer и async снимают блокировку, позволяя качать скрипт в фоне. Resource hints дают сканеру явные приоритеты: preconnect заранее открывает дорогое TLS-соединение, preload поднимает приоритет нужного файла, prefetch — наоборот, тихо качает про запас. А loading="lazy" вообще откладывает запрос за картинкой до пересечения с областью видимости. Все эти подсказки в сумме сокращают время до первой отрисовки и до интерактивности — те самые метрики, что важны и пользователю, и поисковику.

Частые ошибки

  • Скрипт в head без defer/async. Он блокирует отрисовку и даёт белый экран. По умолчанию добавляйте defer.
  • async там, где важен порядок. async не гарантирует очередь выполнения — зависимые скрипты сломаются. Для них нужен defer.
  • preload без атрибута as. Без as браузер не знает тип ресурса и проигнорирует подсказку или скачает дважды.
  • Предзагрузка всего подряд. Десяток preload отнимает канал у главного и замедляет страницу. Берегите приоритет для критичного.
  • lazy на главной картинке. Изображение первого экрана нужно показать сразу — lazy его, наоборот, задержит.
  • img без width/height. При ленивой загрузке страница «прыгает» — всегда задавайте размеры.

Итоги

  • Скорость загрузки влияет и на удобство, и на ранжирование в поиске.
  • defer — выбор по умолчанию для своих скриптов; async — для независимых сторонних.
  • Resource hints (preconnect, preload, prefetch) ускоряют доступ к ресурсам, но их нельзя ставить на всё подряд.
  • <link rel="manifest"> и favicon в head задают иконку и делают сайт устанавливаемым PWA.
  • loading="lazy" откладывает картинки ниже экрана (но не главную) и требует заданных width/height.
Проверьте себя
1. У вас несколько собственных скриптов, и порядок их выполнения важен, но они не должны блокировать отрисовку страницы. Какой атрибут выбрать?
Aasync — он самый быстрый и всегда лучше
Bdefer — скрипты грузятся параллельно, но выполняются после построения страницы и в порядке подключения
CНикакой, оставить обычный <script> в head
Dpreload вместо script
2. Что делает <link rel="preconnect" href="https://fonts.example.com">?
AСкачивает все шрифты с домена и кэширует их
BЗаранее устанавливает соединение (DNS + TLS) с указанным доменом, чтобы сократить задержку при будущих запросах
CОткладывает загрузку шрифтов до конца страницы
DЗапрещает странице обращаться к другим доменам
3. К какой картинке НЕ стоит применять loading="lazy"?
AК большой главной картинке в самом верху страницы (первый экран)
BК картинкам в подвале страницы
CК изображениям глубоко в длинной статье
DК любым картинкам тяжелее 100 КБ