Улучшение крупнейшей отрисовки контента в экосистеме JavaScript.
В рамках проекта Aurora компания Google работала с популярными веб-фреймворками, чтобы обеспечить их хорошую производительность согласно данным Core Web Vitals . В Angular и Next.js уже реализована встраивание шрифтов, о чем рассказывается в первой части этой статьи. Вторая оптимизация, которую мы рассмотрим, — это критическая встраивание CSS, которая теперь включена по умолчанию в Angular CLI и находится в стадии разработки в Nuxt.js.
Встраивание шрифтов
Проанализировав сотни приложений, команда Aurora обнаружила, что разработчики часто включают шрифты в свои приложения, ссылаясь на них в элементе <head>
файла index.html
. Вот пример того, как это будет выглядеть при включении значков материалов:
<!doctype html>
<html lang="en">
<head>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
...
</html>
Несмотря на то, что этот шаблон полностью действителен и функционален, он блокирует отрисовку приложения и вводит дополнительный запрос. Чтобы лучше понять, что происходит, взгляните на исходный код таблицы стилей, указанной в HTML-коде выше:
/* fallback */
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/font.woff2) format('woff2');
}
.material-icons {
/*...*/
}
Обратите внимание, что определение font-face
ссылается на внешний файл, размещенный на fonts.gstatic.com
. При загрузке приложения браузер сначала должен загрузить исходную таблицу стилей, указанную в заголовке.
Затем браузер загружает файл woff2
и, наконец, может приступить к рендерингу приложения.
Возможность оптимизации — загрузить исходную таблицу стилей во время сборки и встроить ее в index.html
. Это пропускает весь путь к CDN во время выполнения, сокращая время блокировки.
При создании приложения в CDN отправляется запрос, который извлекает таблицу стилей и встраивает ее в HTML-файл, добавляя <link rel=preconnect>
в домен. Применив эту технику, мы получим следующий результат:
<!doctype html>
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin >
<style type="text/css">
@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/font.woff2) format('woff2');}.material-icons{/*...*/}</style>
...
</html>
Встраивание шрифтов теперь доступно в Next.js и Angular.
Когда разработчики инфраструктуры реализуют оптимизацию в базовых инструментах, они упрощают ее использование существующими и новыми приложениями, внося улучшения во всю экосистему.
Это улучшение включено по умолчанию в Next.js v10.2 и Angular v11. Оба поддерживают встраивание шрифтов Google и Adobe. Angular планирует представить последний в версии 12.2.
Вы можете найти реализацию встраивания шрифтов в Next.js на GitHub , а также посмотреть видео, объясняющее эту оптимизацию в контексте Angular .
Встраивание критического CSS
Еще одно улучшение включает в себя улучшение показателей «Первая отрисовка контента» (FCP) и «Наибольшая отрисовка контента» (LCP) путем встраивания критического CSS. Критический CSS страницы включает в себя все стили, использованные при ее первоначальном рендеринге. Чтобы узнать больше об этой теме, ознакомьтесь с статьей «Отложить некритичный CSS» .
Мы заметили, что многие приложения загружают стили синхронно, что блокирует рендеринг приложений. Быстрое решение — асинхронная загрузка стилей. Вместо загрузки сценариев с помощью media="all"
установите для атрибута media
значение print
, а после завершения загрузки замените значение атрибута на all
:
<link rel="stylesheet" href="..." media="print" onload="this.media='all'">
Однако такая практика может привести к мерцанию неоформленного контента.
На видео выше показан рендеринг страницы, стили которой загружаются асинхронно. Мерцание происходит потому, что браузер сначала начинает загрузку стилей, а затем отображает последующий HTML. Как только браузер загружает стили, он запускает событие onload
элемента link, обновляя атрибут media
до all
и применяя стили к DOM.
В период между отрисовкой HTML и применением стилей страница частично не имеет стилей. Когда браузер использует стили, мы видим мерцание, что неприятно для пользователя и приводит к регрессии в накопительном сдвиге макета (CLS) .
Критическая встраивание CSS вместе с асинхронной загрузкой стилей может улучшить поведение загрузки. Инструмент critters определяет, какие стили используются на странице, просматривая селекторы в таблице стилей и сопоставляя их с HTML. Когда он находит совпадение, он рассматривает соответствующие стили как часть критического CSS и встраивает их.
Давайте посмотрим на пример:
<head> <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'"> </head> <body> <section> <button class="primary"></button> </section> </body>
/* styles.css */ section button.primary { /* ... */ } .list { /* ... */ }
В приведенном выше примере твари будут читать и анализировать содержимое styles.css
, после чего они сопоставляют два селектора с HTML и обнаруживают, что мы используем section button.primary
. Наконец, твари встроят соответствующие стили в <head>
страницы, в результате чего:
<head> <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'"> <style> section button.primary { /* ... */ } </style> </head> <body> <section> <button class="primary"></button> </section> </body>
После встраивания критического CSS в HTML вы обнаружите, что мерцание страницы исчезло:
Критическая встраивание CSS теперь доступно в Angular и включено по умолчанию в версии 12. Если вы используете версию 11, включите ее, установив для свойства inlineCritical
значение true
в angular.json
. Чтобы включить эту функцию в Next.js, добавьте experimental: { optimizeCss: true }
в ваш next.config.js
.
Выводы
В этом посте мы коснулись некоторых аспектов сотрудничества между Chrome и веб-фреймворками. Если вы являетесь автором фреймворка и знаете некоторые проблемы, которые мы решили в вашей технологии, мы надеемся, что наши результаты вдохновят вас применить аналогичные оптимизации производительности.
Узнайте больше об улучшениях . Полный список работ по оптимизации, которые мы проделали для Core Web Vitals, можно найти в статье «Введение в Aurora» .