В 2021 году Google сформировал Web Vitals — представление о сигналах качества сайта, отражение того, насколько удобно пользователям с ним взаимодействовать. Core Web Vitals — набор показателей для количественного измерения этого удобства.
Кратко самое важное про Core Web Vital
В набор показателей Core Web Vitals входит измерение времени загрузки элементов страницы, отзывчивость контента на действия пользователей и стабильность этого контента во время загрузки.
LCP (Largest Contentful Paint) — загрузка самого большого видимого объекта на видимой пользователю области экрана. Хорошим показателем считается 2,5 секунды с начала загрузки страницы.
CLS (Cumulative Layout Shift) — визуальная стабильность, смещение макета страницы во время загрузки элементов. Приемлемый показатель CLS — 0,1 или меньше.
FID (First Input Delay) — интерактивность, время реакции страницы на первое действие пользователя. Хороший уровень FID — до 100 миллисекунд.
Подробнее Core Web Vitals мы разбирали в материале.
CSS тоже могут влиять на Core Web Vitals, особенно это касается показателей LCP — отрисовки самого большого видимого элемента, и CLS — сдвига макета.
Проверить скорость загрузки страницы и посмотреть на процесс ее загрузки можно в бесплатном инструменте от PR-CY.
Как оптимизировать CSS для быстрой загрузки страниц:
Для удобства методы разбиты по элементам, с которыми нужно работать: макет, изображения, шрифты, анимация — все касается работы со стилями. За основу взяли статью «CSS для Web Vitals» Кэти Хемпениус и Уны Кравец, перевели и дополнили полезными решениями.
1. Критические и некритические CSS
При обработке CSS по умолчанию блокируется рендеринг — визуализация страницы. Пока браузер не загрузит и не проанализирует таблицу стилей, он не будет загружать другие ресурсы. Если файлы CSS большие или есть проблемы с сетью, показатель LCP может ухудшиться, потому что затянется загрузка наибольшего видимого объекта.
Как оптимизировать CSS
Производительность можно повысить, если разделить CSS на критически важные для загрузки первого экрана и остальные, которые можно отложить.
Верхняя строка отображает загрузку страницы с CSS, блокирующим рендеринг. Нижняя — загрузка той же страницы со встроенным критическим CSS:
Как работать с CSS страницы
Критические CSS вынести в head
CSS, нужные для загрузки верхней части первого экрана, нужно как можно быстрее отобразить пользователям. Встройте их в head, чтобы для получения этих стилей не требовался дополнительный запрос.Встроенный критический CSS Некритические CSS загрузить асинхронно
Остальную часть CSS, которая не требуется для начального рендеринга страницы, можно загрузить асинхронно с помощью loadCSS или отложить в footer.Неиспользуемые CSS
Ненужные CSS удалить или переместить в другую таблицу стилей, если для других страниц сайта они все-таки нужны. Лучше не делать это вручную, можно удалить что-то нужное.
В статье про оптимизацию LCP мы разобрали, как автоматизировать этот способ оптимизации стилей. Смотрите раздел «Блокировка рендеринга JavaScript и CSS»
У способа есть и недостатки: браузер не будет кэшировать встроенный в head CSS, так что каждый раз он будет загружаться заново. Проверьте, возможно, у вас нет проблем с рендерингом, так что и разделять CSS вам не нужно.
Еще можно минифицировать CSS, то есть сократить, тем самым уменьшив размер файла. После минификации в файле не будет лишних пробелов и ненужных символов. Бесплатные инструменты для этого собрали в статье об ускорении загрузки.
2. Изображения
Рассмотрим не оптимизацию изображений в целом, а только проблемы, связанные с CSS и картинками.
Изображения и LCP
LCP — показатель загрузки самого большого элемента на видимом экране. Чаще всего это изображение, хотя самым большим элементом может быть и текст, и видеоролик.
Более того, самый большой элемент страницы может меняться по мере загрузки и появления новых объектов. Или в зависимости от устройства просмотра, как в этом примере. Здесь главными объектами выступают обложка статьи, фон уведомления о файлах cookie и текст статьи:
Как оптимизировать
В примере на планшете самый большой элемент — это фоновое изображение уведомления о файлах cookie. Вместо него можно нарисовать градиент в CSS, чтобы не тратить время на загрузку изображения для фона. Это улучшит LCP.
Измените .banner CSS, чтобы использовать градиент CSS, а не изображение.
Было:
background: url("https://cdn.pixabay.com/photo/2015/07/15/06/14/gradient-845701\_960\_720.jpg")
Стало:
background: linear-gradient(135deg, #fbc6ff 20%, #bdfff9 90%);
Сдвиги макета CLS
Если картинка загружается после отрисовки страницы, а под ее параметры не было зарезервировано место, макет сдвинется. Это будет заметно при медленном интернете или при большом размере файла.
Как исправить
Нужно зарезервировать место в DOM для элемента, появление которого смещает макет.
Можно зарезервировать нужное для картинки пространство с помощью полей соотношения сторон CSS. Если ширина изменится, изменится и высота, сохранив пропорции.
Если известно одно измерение изображения, можно определить второе по его пропорциям. Если картинка шириной 640 пикселей имеет соотношение сторон 16:9, то его высота составит 640 x (9/16) = 360 пикселей. Чтобы не считать самим, есть калькулятор.
Для предотвращения сдвигов макета как раз полезно использовать способ, учитывающий соотношение сторон. Об этом способе есть материал на английском.
Современные браузеры устанавливают соотношение сторон изображений по умолчанию на основе атрибутов ширины и высоты, благодаря CSS. Разработчикам нужно установить width и height как обычно:
<img src="puppy.jpg" width="640" height="360" alt="Puppy with balloons" />
И использовать каскадные CSS для всех браузеров, которые добавят соотношение сторон по умолчанию на основе существующих атрибутов width и height:
img {
aspect-ratio: attr(width) / attr(height);
}
В этом случае браузер вычислит пропорцию картинки, основанную на атрибутах width и height, до загрузки изображения, в самом начале расчета макета. Если изображение имеет определенную ширину (например width: 100%), с помощью соотношения сторон он вычислит его высоту.
Адаптивные изображения
Современный подход к загрузке изображений — использование srcset атрибутов в сочетании с атрибутами width и height. Способ дает дополнительное преимущество в производительности, потому что позволяет обслуживать изображения разного размера на разных устройствах.
Для примера это выглядит так:
<img width="1000" height="1000" src="puppy-1000.jpg" srcset="puppy-1000.jpg 1000w, puppy-2000.jpg 2000w, puppy-3000.jpg 3000w" alt="Puppy with balloons">
О настройте адаптивных изображений есть в статье «Большое руководство по SEO для картинок».
Изображение в контейнере
Если изображение находится в контейнере, вы можете использовать CSS, чтобы изменить размер изображения до ширины этого контейнера. Прммер: установили height: auto, чтобы высота изображения не была фиксированным значением:
img {
height: auto;
width: 100%;
}
3. Реклама, скрипты, фреймы
История такая же, как в предыдущем пункте про изображения. Если какой-то элемент появляется в DOM после того, как окружающая страница уже отрисована, он сдвинет контент под ним. Типичные примеры — появление в верхней части страницы рекламы, фреймов, в целом сторонних скриптов, когда элементы ниже уже загрузились.
Как реклама может портить CLS:
сайт вставляет рекламный контейнер в DOM;
сайт меняет размер рекламного контейнера с помощью собственного кода;
рекламное объявление заполняет контейнер, но оказывается другого размера.
Динамические элементы тоже могут смещать контент. К примеру, это часто происходит из-за форм и баннеров «подпишитесь на рассылку», «другой контент по теме», «установите наше приложение», «закажите у нас» и других.
Посмотреть, какие элементы влияют на смещение макета страницы можно в бесплатном инструменте для проверки скорости. Он анализирует загрузку страницы поэтапно и дает подсказки, как оптимизировать каждый этап.
Как решить проблему
Рекламные блоки и фреймы
Зарезервировать место для рекламы или фрейма, чтобы никакой контент не занял этот слот, пока элементы не загрузились.
Если слот для рекламы есть, но само объявление не появилось, не стоит сворачивать этот рекламный слот на странице. Лучше показывать там заглушку, чтобы не сдвигать контент.
Если в слоте под рекламу появляются объявления разного размера, ориентируйтесь на максимально возможный размер, когда резервируете место, чтобы не обрезать объявления. Максимально возможный из тех, что когда-либо появлялись в этом блоке.
Динамический контент
Не стоит загружать новый контент над уже загруженным и прочитанным пользователями. Скорее всего появление нового блока сверху будет для них неожиданностью. Исключением могут быть элементы, которые появились в ответ на действие пользователя и ожидаются вверху экрана.
Если такой блок нужен вверху, также зарезервируйте для него место на странице.
Уведомления cookie
Бывает, что источником сдвигов макета выступают уведомления о согласии на использование файлов cookie, если они находятся в верхней части экрана. Как можно с ним поработать:
Использовать липкий колонтитул или модальное окно для уведомления о файлах cookie. При этих подходах уведомление появится наложением поверх остальной части страницы и тогда оно не будет вызывать смещение макета при загрузке.
Само уведомление лучше перенести вниз и настроить фиксированное или абсолютное позиционирование. При фиксированном элемент закрепится и во время прокрутки страницы будет всегда виден посетителю, а при абсолютном будет перемещаться с документом при прокрутке. Такое уведомление перекроет статичные элементы, даже если будет находиться ниже в коде.
Было:
.banner {
position: sticky;
top: 0;
}
Стало:
.banner {
position: fixed;
bottom: 0;
}
- Скрипты, которые загружаются не асинхронно, будут задерживать загрузку страницы и портить показатель LCP. Поэтому нужно настроить асинхронную загрузку, чтобы она не влияла на основной поток рендера. Для этого нужно добавить async в тег элемента:
<script src="https://cookie-notice.com/script.js" async>
4. Шрифты
Увидеть шрифты, которые загружаются на определенной странице, можно в браузерном режиме просмотра кода страницы. Перейдите на вкладку Network и выберите фильтр по Font:
Узнать, сколько времени требуется для запроса шрифта, можно на вкладке «Timing». Чем раньше запрошен шрифт, тем скорее его можно будет загружать и использовать. Цепочка запросов на шрифт отображается на вкладке «Initiator», чем она короче, тем быстрее можно будет запросить шрифт.
Применение шрифтов может задерживать рендеринг текста и вызывать сдвиги макета. Посмотрим, какие проблемы могут возникнуть и как их решать.
Как работать со шрифтами
Как оптимизировать рендеринг
Есть два варианта рендеринга шрифтов:
Резервный невидимый шрифт —> основной шрифт
Текст рендерится с доступным системе шрифтом, но он не видим пользователю до загрузки. Когда основной шрифт загружается, текст становится виден на странице. В это время может быть заметно FOIT — мигание невидимого текста.
В этом случае сдвиг макета минимальный, но скорость загрузки будет ниже, может задержаться первая отрисовка содержимого — FCP, а иногда и отрисовка самого большого объекта — LCP.Системный шрифт —> основной шрифт
Текст рендерится с доступным шрифтом, но видимым пользователям, а после загрузки шрифт подменяется. Может быть заметно ощутимое мигание нестилизованного текста — FOUT.
При этом способе загрузка быстрее, но сдвиг более вероятен.
У PageSpeed Insights есть замечание «Настройте показ всего текста во время загрузки веб-шрифтов», то есть инструмент советует второй вариант.
Для этого в CSS шрифта нужно добавить свойство «font-display:swap», чтобы до загрузки файла вашего шрифта текст отображался системным шрифтом.
В нужном CSS-файле шрифта будут правила font-face с прописанными путями к файлам шрифта. Внутрь этого правила и нужно вставить «font-display:swap».
К примеру:
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url('../fonts/open-sans-v18-cyrillic-regular.eot'); /* IE9 Compat Modes */src: local(''),
url('../fonts/open-sans-v18-cyrillic-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/open-sans-v18-cyrillic-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/open-sans-v18-cyrillic-regular.woff') format('woff'), /* Modern Browsers */
url('../fonts/open-sans-v18-cyrillic-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/open-sans-v18-cyrillic-regular.svg#OpenSans') format('svg'); /* Legacy iOS */
font-display:swap /* Нужно добавить эту строку */}
Стили внешних Google-шрифтов редактировать не получится. Нужно сделать правку в файле, где записан адрес шрифта: в конец адреса добавить параметр display=swap.
https://fonts.googleapis.com/css?family=Montserrat:100&display=swap
Для сайтов на WordPress есть плагины.
Полезный сервис: Transfonter в ответ на файл шрифта выдаст архив со всеми форматами и корректный CSS.
Как избежать смещения макета
Замена резервного шрифта на основной может повлиять на CLS — смещение макета, если основной и резервный шрифты занимают разное пространство на странице. В этом примере замена шрифта привела к смещению элементов страницы вверх на пять пикселей:
Минимизировать эти сдвиги можно, если подобрать шрифты с одинаковыми пропорциями букв.
Предзагрузка
Без предзагрузки браузер сначала прочитает страницу, увидит указание на CSS, скачает его, разберет, найдет блок с описанием шрифтов и только потом начнет их загружать. Из-за этого могут быть сдвиги макета и в целом замедление загрузки.
Файлы шрифтов можно предзагрузить. Если браузер увидит объявление о предзагрузке шрифта, он будет загружать и его, и параллельно CSS. К моменту, как он разберет CSS, шрифт уже будет доступен для рендера.
Для WordPress есть плагины, либо можно использовать link rel = "preload" as = "font".
<link rel="preload" as="font" href="roboto.woff2?v=4.5.0" crossorigin>
В примере есть версия шрифта v=4.5.0. Ее нужно использовать в preload, если Google показывает версию в адресе.
Что касается Google Fonts, то он предоставляет возможность загружать шрифты с помощью тегов link или операторов @import. Подсказка preconnect в теге link должна привести к более быстрой загрузке таблиц стилей, чем при использовании @import.
Удалите из таблицы стилей этот оператор @import:
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400&family=Roboto:wght@300&display=swap');
И добавьте в head документа эти теги link:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap" rel="stylesheet">
Эти теги подсказывают браузеру, что нужно установить раннее соединение с источниками, используемыми Google Fonts, и загрузить таблицу стилей шрифтов Montserrat и Roboto.
Есть и другие способы ускорить загрузку страницы и оптимизировать все параметры, входящие в Core Web Vitals. Но эти улучшения, касающиеся CSS, тоже могут сделать страницу значительно удобнее и приятнее для пользователей.
Расскажите в комментариях, как вы оптимизируете CSS?