Четыре сотни в PageSpeed, и что именно для этого понадобилось
Google PageSpeed Insights даёт этому сайту 100 баллов за производительность, доступность, лучшие практики и SEO - и на десктопе, и на мобильном. Вместо того чтобы выложить скриншот и на этом закончить, вот каждое изменение, которое к этому привело.
Если вы работали в электронной коммерции, вы и так знаете, почему это важно, и дело не столько в SEO. Скорость страницы видна в конверсии, в отказах и в том, сколько людей вообще доходит до второго шага воронки. Это одна из немногих технических цифр, которая без споров переводится в выручку.
Самое впечатляющее, что мы видели вживую, - платформа электронной коммерции примерно с восемью миллионами товаров, отдававшая страницу примерно за семь десятых секунды. Пять лет назад честным объяснением такого результата была бы команда инженеров мирового уровня и соответствующий бюджет. Сейчас это достижимее - лучше настройки по умолчанию, лучше инструменты и заметно меньше написанного вручную клея, - но это по-прежнему не бесплатно и по-прежнему состоит из десятков мелких решений, а не из одного ловкого приёма.
Итак: PageSpeed Insights, четыре сотни, десктоп и мобильный. Вот что за ними стоит.
Начните с того, чтобы не отгружать фреймворк
Этот сайт - статический HTML с одной таблицей стилей и одним скриптом. Нет клиентского роутера, нет шага гидратации, нет рантайма компонентов. Это решение стоит больше, чем все перечисленные ниже оптимизации вместе взятые, потому что самый быстрый JavaScript - тот, который так и не был отправлен.
Это не аргумент против фреймворков вообще: мы делаем множество приложений, где фреймворк полностью оправдан. Это аргумент против того, чтобы хвататься за него ради одиннадцати маркетинговых страниц, которые между деплоями не меняются.
Между HTML и первой отрисовкой не стоит ничего
Таблица стилей минифицируется на сборке и встраивается в каждую страницу элементом
<style>. Отдельный CSS-файл означал бы второй круг обращений до того,
как хоть что-то можно нарисовать, а таблица достаточно мала, чтобы байты стоили дешевле
запроса. То есть первый же ответ содержит всё необходимое для отрисовки.
Montserrat размещён у нас как вариативный woff2, латиница и расширенная латиница, веса от 400 до 800 в одном файле. Никакого рукопожатия со сторонним шрифтовым сервисом, никакого DNS-запроса к чужому домену до того, как появится текст. Каждая страница предзагружает латинский поднабор.
Три вещи, которые раньше работали, пока читатель ждал
Отсюда и пришла большая часть измеримого выигрыша.
-
WebGL-шейдер. Стеклянный эффект за карточками шагов на главной
компилирует фрагментный шейдер, и это блокировало главный поток почти на секунду.
Секция, которую он украшает, находится далеко ниже первого экрана, поэтому
IntersectionObserverтеперь придерживает его, пока читатель не окажется в двух экранах от неё. -
Google Tag Manager. Около 120 КБ стороннего JavaScript, от которого
на странице ничего не зависит.
dataLayerпо-прежнему создаётся сразу, поэтому ни одно событие не теряется, но сам контейнер подгружается по первому взаимодействию или когда браузер после загрузки уходит в простой - что наступит раньше. -
Миниатюры шагов. Примерно 590 КБ анимированных GIF, которые видны
только на раскрытой карточке. Они хранят свой адрес в
data-src, и скрипт подставляетsrc, когда карточка открывается. На устройствах с курсором весь ряд прогревается при наведении, так что раскрытие всё равно ощущается мгновенным.
Картинки: скучные 400 КБ
Крупные декоративные изображения отдаются в AVIF с оригиналом как запасным вариантом
через <picture>, и только на главной это около 400 КБ.
Одна ловушка, которую стоит передать дальше. CSS-фон не получает такой же
обработки: он остаётся обычным url() в формате, который читает любой
браузер. image-set() вместе с type() корректно разбирается
только начиная с Safari 17 - более старый Safari принимает объявление и затем не рисует
ничего. Все фоновые изображения кейсов для таких посетителей молча исчезали, хотя в
Chrome всё выглядело идеально. Наша сборка теперь отказывается работать, если в таблице
стилей встречается image-set(. Выбор формата - дело
<picture>, где все браузеры ведут себя правильно уже десять лет.
Две вещи, которые мы проверяем перед любым перекодированием:
- В каком размере это реально отображается? Одна фотография товара была оригиналом 3072 × 4096, который показывали в блоке 624 × 680.
-
Градиенту не нужно разрешение. Затемняющий слой над каждым заголовком
кейса весил 557 КБ при 2880px. При 1440px в AVIF он весит 8 КБ и отличается от
оригинала в пределах трёх единиц, потому что
background-size: coverрастягивает его в любом случае.
У каждого <img> проставлены явные width и
height, поэтому при загрузке ничего не прыгает. Это половина оценки,
связанная со сдвигом макета, и она достаётся бесплатно. Плюс
loading="lazy" и decoding="async".
Видео, на котором сайты обычно и проигрывают
За заголовком крутится зацикленная стеклянная анимация. Она же - самое тяжёлое на странице, поэтому к ней относятся как к необязательной.
Кадр-постер рисуется средствами CSS как фон секции, поэтому заголовок никогда не пустой, а видео никогда не входит в первую отрисовку. Каждый ролик закодирован четырьмя способами - 1080p и 720p, каждый в H.264 и HEVC, - и скрипт выбирает наименьший файл, который покрывает отображаемый размер, предварительно проверив, умеет ли браузер декодировать HEVC. Телефон никогда не скачивает декоративный фон в 1080p.
Оно полностью пропускается при prefers-reduced-motion или Save-Data, ждёт
события load, а всё, что ниже первого экрана, ждёт, пока не окажется в
пределах одного экрана от видимости. Откройте любую нашу страницу с середины - и видео
заголовка не загрузится вовсе.
Кеширование, которое ничего не стоит настроить правильно
Годовой неизменяемый кеш для статики, no-cache для HTML и сжатие для всего
текстового. В адресах ресурсов стоит версия, поэтому изменённый файл - это изменённый
адрес, и длинный кеш никогда не оказывается обманом.
Остальные три сотни - это не производительность
Доступность, лучшие практики и SEO - это скорее дисциплина, чем инженерия, и поддерживать их куда дешевле, чем потом дорабатывать.
-
Один
h1на страницу, секции -h2, карточки -h3, и ни одна секция не выдумывает себе собственный размер заголовка, чтобы выглядеть важнее. -
Ссылка пропуска, настоящие ориентиры,
aria-labelledbyу каждой секции, видимые состояния фокуса и контраст, проверенный против того фона, на котором элемент действительно находится, а не того, под который его рисовали. -
Канонический адрес и
hreflangна каждой странице, во всех трёх языках, и каждая страница объявляет себя среди собственных альтернатив. -
Структурированные данные, собранные из того же источника, что и видимая страница,
поэтому разметка и содержание не могут разойтись. Наша страница вопросов и её схема
FAQPageсобираются из одного массива; второй копии, которую можно забыть обновить, просто нет.
Чего оценка не говорит
Стоит сказать прямо: PageSpeed - это лабораторное измерение на смоделированном устройстве и соединении. Это хороший ориентир и действительно полезный чек-лист, но значение имеют полевые данные от настоящих посетителей в настоящих сетях. Идеальный лабораторный результат без полевых данных за спиной - это хороший скриншот, а не законченная работа.
И он не навсегда. Добавьте один сторонний скрипт, одну картинку без размеров, один шрифт с чужого CDN - и его нет. Полезный итог здесь не четыре сотни. Полезный итог - сборка, в которой быстрый вариант является вариантом по умолчанию, поэтому оценка переживёт следующего человека, который будет править сайт.
И да: когда PageSpeed выдаёт четыре сотни, скриншот делают до того, как он передумает.