Мобильный телефон не пользуется стилями для широкого экрана — но обычно всё равно ждёт их загрузки. CSS в <head> блокирует отрисовку целиком, вместе со всеми @media (min-width: 1200px), которые на телефоне никогда не сработают. Это можно разделить: мобильные стили — блокирующим файлом, десктопные — отдельным, который телефон не ждёт.

Это тридцатая часть цикла «PageSpeed без мифов».

Как это работает

Браузер не блокирует отрисовку стилями, чьё условие media не подходит устройству. Такой файл он всё равно скачает, но с низким приоритетом и не дожидаясь его:

<!-- мобильная база: нужна всем, блокирует отрисовку -->
<link rel="stylesheet" href="/css/main.css">
<!-- правила для широких экранов: телефон их не ждёт -->
<link rel="stylesheet" href="/css/main.mq.css" media="(min-width: 560px)">

Делить вручную неудобно, поэтому это делает сборка: плагин проходит по готовому CSS, выносит все правила внутри @media (min-width: …) в файл .mq.css и запоминает самый низкий порог — его и пишет в атрибут media. Условие одно: стили должны быть написаны «от мобильного» (mobile-first), когда база — для телефона, а широкие экраны добавляются через min-width.

Результат

На одном сайте после включения разделения: Speed Index 4,4 → 1,8 с, «задержка отрисовки» LCP 1870 → 270 мс, и «блокирующий CSS» пропал из верха отчёта.

Три грабли

1. Делить только стили, которые грузятся сразу

Если разделить стили компонента, который подключается иногда синхронно, а иногда динамически (скриптом), то при динамической загрузке десктопная половина может не приехать. Делите только начальные файлы страницы.

2. Разделение может молча выключиться

У нас был случай: сборка прошла, файлы .mq.css появились, но связка «какой файл к какому» не записалась в манифест сборки — и сайт продолжил отдавать полный блокирующий CSS. Снаружи это выглядело как «фича выключена». Проверка после каждой сборки и выката:

# в манифесте есть связки разделения
grep -c mediaSplit assets-dist/manifest.json
# на странице есть link с media
curl -s https://example.ru/ | grep -c 'media=.(min-width'

3. На боевой сайт уезжает сборка из CI, а не ваша

Если сайт собирается в CI, настройки сборки должны быть в репозитории. Флаг, включённый только в локальном файле окружения, на сервере не сработает — и на тесте вы увидите 1,8 с, а на сайте останется 4,4.

Побочный эффект в каскаде. Десктопный файл подключается после базового, поэтому его правила побеждают при равной специфичности — независимо от порядка в исходнике. Это может неожиданно переопределить стили. Подробно — в следующей части.

«Блокирующий CSS» не уходит из отчёта?

Пришлите адрес — проверю, можно ли разделить стили и не выключилось ли разделение.

· полезно?
АЧ
Алексей Чикун веб-разработчик, команда TRIOHEAD

Делаю сайты и сервисы целиком: от вёрстки до сервера. Пишу о том, что проверил на своих проектах.

Комментарии

// загружаю комментарии…

Комментарии публикуются после проверки. Ссылки и HTML не принимаются.