Улучшение отрисовки самого большого содержимого в экосистеме JavaScript.
В рамках проекта Aurora Google работает с популярными веб-фреймворками, чтобы гарантировать их хорошую работу в соответствии с Core Web Vitals . Angular и Next.js уже внедрили встраивание шрифтов, которое объясняется в первой части этой статьи. Вторая оптимизация, которую мы рассмотрим, — это критическое встраивание CSS, которое теперь включено по умолчанию в Angular CLI и находится в стадии разработки в реализации в Nuxt.js.
Встраивание шрифта
Проанализировав сотни приложений, команда Aurora обнаружила, что разработчики часто включают шрифты в свои приложения, ссылаясь на них в элементе <head> index.html . Вот пример того, как это будет выглядеть при включении Material Icons:
<!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 ожидает, что последний будет представлен в v12.2.
Реализацию встраивания шрифтов в Next.js можно найти на GitHub , а также посмотреть видео, объясняющее эту оптимизацию в контексте Angular .
Встраивание критического CSS
Другое улучшение включает улучшение метрик First Contentful Paint (FCP) и Largest Contentful Paint (LCP) путем встраивания критического CSS. Критический CSS страницы включает все стили, используемые при ее первоначальном рендеринге. Чтобы узнать больше об этой теме, ознакомьтесь с разделом Defer non-critical CSS .
Мы заметили, что многие приложения загружают стили синхронно, что блокирует рендеринг приложения. Быстрое решение — загружать стили асинхронно. Вместо загрузки скриптов с media="all" установите значение атрибута media на print , а после завершения загрузки замените значение атрибута на all :
<link rel="stylesheet" href="..." media="print" onload="this.media='all'">
Однако такая практика может привести к мерцанию нестилизованного контента.
Видео выше показывает рендеринг страницы, которая загружает свои стили асинхронно. Мерцание происходит потому, что браузер сначала начинает загрузку стилей, а затем рендерит HTML, который следует за ними. Как только браузер загрузит стили, он запускает событие onload элемента ссылки, обновляя атрибут 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 { /* ... */ }
Пример перед встраиванием.
В приведенном выше примере critters прочитает и проанализирует содержимое styles.css , после чего сопоставит два селектора с HTML и обнаружит, что мы используем section button.primary . Наконец critters встроит соответствующие стили в <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 и включена по умолчанию в v12. Если вы используете v11, включите ее, установив свойство inlineCritical в true в angular.json . Чтобы включить эту функцию в Next.js, добавьте experimental: { optimizeCss: true } в ваш next.config.js .
Выводы
В этой статье мы коснулись некоторых аспектов сотрудничества между Chrome и веб-фреймворками. Если вы являетесь автором фреймворка и узнаете некоторые из проблем, с которыми мы столкнулись в вашей технологии, мы надеемся, что наши выводы вдохновят вас на применение аналогичных оптимизаций производительности.
Узнайте больше об улучшениях . Полный список работ по оптимизации, которые мы проделали для Core Web Vitals, можно найти в посте Знакомство с Aurora .