Современный веб медленный, но у нас есть несколько простых стратегий по ускорению наших сайтов. Одна из них это инлайнирование критичного CSS внутри <head> на странице, но что делать если ваш сайт состоит из сотен страниц или, что хуже, использует сотни различных шаблонов? Вы не сделаете это вручную. Дин Хьюм объясняет простой способ решения этой проблемы. Если вы опытный разработчик, вам эта статья покажется очевидной, но ее стоит показать вашим клиентам и junior-разработчикам.

Обеспечение быстрой и гладкой работы это важная часть создания сайтов. Большую часть времени мы разрабатываем сайты без понимания, что происходит “под капотом” браузера. Как на самом деле происходит рендеринг страниц из нашего HTML, CSS и JavaScript? И как мы можем использовать это знание для ускорения рендеринга веб-страниц?

Если мне надо быстро улучшить производительность сайта, то я начинаю работу с использования Google PageSpeed. Этот инструмент может здорово помочь при профилировании страницы и поиске участков, которые можно оптимизировать. Просто введите адрес страницы, которую вы хотите протестировать и вы получите список рекомендаций по улучшению производительности.

Если вы когда-либо прогоняли один из своих сайтов через PageSpeed Insights, то вы уже могли столкнуться с подобным отчетом:

PageSpeed Insights

CSS и JavaScript блокируют рендеринг страницы. (Увеличенная версия)

Я должен признаться, что первый раз был смущен, когда увидел подобный итог, текст гласит:

Контент страницы не может быть выведен без ожидания загрузки следующих ресурсов. Попробуйте использовать отложенную или асинхронную загрузку блокирующих ресурсов или инлайнируйте критически важные части ресурсов напрямую в HTML.

К счастью, решение этой проблемы проще, чем кажется. Ответ лежит в способе загрузки CSS и JavaScript на вашу страницу.

Что такое критичный CSS?

Запрос к файлу CSS может значительно увеличить время рендеринга страницы. Причиной этого является то, что по умолчанию браузер откладывает рендеринг страницы до окончания загрузки, парсинга и применения всех файлов CSS, указанных в <head> страницы. Это происходит потому, что браузеру нужно расчитать раскладку вашей страницы.

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

Критический путь рендеринга это шаги, которые делает браузер делает для рендеринга страницы. Нам нужно свести к минимуму количество блокирующего CSS, или критичного CSS, чтобы наша страница быстрее показалась пользователю. Критический ресурс это любой ресурс, который может блокировать первоначальный рендеринг страницы. Идея состоит в том, чтобы веб-сайт мог вывести первые элементы контента пользователю в первых TCP-пакетах. Чтобы получить краткое представление о том, как это работает на странице, взгляните на рисунок ниже:

Критичный и некритичный контент

Критичный CSS это минимальный набор блокирующего CSS, требуемого для рендеринга первого экрана с контентом пользователю. (Увеличенная версия)

В этом примере, критичной является только та часть страницы, которую видит пользователь при первоначальной загрузке. Это значит, что нам нужно загрузить минимальное количество CSS, необходимого для рендеринга верхней части страницы для всех контрольных точек. За оставшуюся часть CSS не стоит беспокоиться, мы загрузим ее асинхронно.

Как мы можем определить, что считать критичным CSS? Определение критичного CSS для страницы это процесс достаточно сложный и требующий прохода по DOM страницы. Затем нам надо определить список стилей, которые применены к каждому видимому элементу. Это трудоемкий процесс, но существуют инструменты для его автоматизации.

В этой статье я покажу вам как улучшить скорость рендеринга страницы за счет критичного CSS и расскажу вам об инструментах, автоматизирующих этот процесс.

Критичный CSS в действии

Для начала работы с критичным CSS вашей страницы, нам надо изменить подход к обработке CSS, это значит, что нам надо разбить его на 2 файла. В первом файле у нас будет набор необходимого CSS, который мы впоследствии инлайнируем. А во втором весь оставшийся некритичный CSS, который мы будем асинхронно загружать на страницу.

Это может показаться странным поначалу, но инлайнирование критичного CSS в HTML позволяет сгладить острые углы критического пути. Это позволяет доставить критичный CSS в один заход и представить сайт пользователям максимально быстро.

Чтобы понять, как должен выглядеть HTML, взгляните на этот простой пример:

<!doctype html>
<head>
  <style> /* inlined critical CSS */ </style>
  <script> loadCSS('non-critical.css'); </script>
</head>
<body>
  ...body goes here
</body>
</html>

В этом коде мы извлекли критичный CSS и инлайнировали его в HTML между тегами style. Затем, мы используя функцию loadCSS(); асинхронно загружаем оставшийся, некритичный CSS. Это важно, потому что мы существенно уменьшаем нагрузку за счет некритичного CSS, который мы вставляем на страницу в фоновом режиме.

Поначалу это кажется кошмаром для поддержки. Кому захочется вручную инлайнировать фрагмент CSS на каждой странице? Хорошие новости — процесс можно автоматизировать и в этом примере я использовал Critical. Этот инструмент создал Эдди Османи это пакет Node.js, позволяющий автоматически извлекать и инлайнировать критичный CSS из HTML-страниц.

Мы будем комбинировать его с grunt, диспетчером задач JavaScript для автоматизации обработки CSS. Если вы никогда не использовали Grunt раннее, на сайте есть неплохая детальная документация, а также много советов по настройке вашего проекта. Я также раннее писал об этом инструменте.

Приступаем к работе

Давайте начнем с консоли и перехода в каталог вашего сайта. Установите интерфейс командной строки Grunt, введя следующую команду (может потребовать sudo):

npm install -g grunt-cli

Это добавит команду grunt к системному пути, позволяя вам запускать его из любого каталога. Затем установите сам Grunt:

npm install grunt --save-dev

Затем установите плагин grunt-critical:

npm install grunt-critical --save-dev

Затем вам надо создать Gruntfile.js с конфигурацией для вашего проекта. Вот образец моего грантфайла:

module.exports = function (grunt) {

grunt.initConfig({
  critical: {
    dist: {
      options: {
        base: './'
      },
      // The source file
      src: 'page.html',
      // The destination file
      dest: 'result.html'
      }
    }
  });

  // Load the plugins
  grunt.loadNpmTasks('grunt-critical');

  // Default tasks.
  grunt.registerTask('default', ['critical']);
};

В этом коде я поставил Grunt задачу наблюдать за моим файлом page.html, затем он обработает CSS на этой странице и вычислит критичный, а в финале инлайнирует критичный CSS и соответственно обновит страницу HTML.

Запустите плагин, набрав grunt в консоли:

автоматизация с Grunt

Автоматизация производительности с помощью Grunt. (Увеличенная версия

Если вы теперь посмотрите на содержимое каталога, то заметите файл result.html , содержащий весь критичный CSS и асинхронно подгружающий остальные стили. Ваша веб-страница готова к рок-н-роллу!

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

critical: {
  dist: {
    options: {
      base: './',
      dimensions: [{
        width: 1300,
        height: 900
      },
      {
        width: 500,
        height: 900
      }]
    },
    files: [
      {src: ['index.html'], dest: 'dist/index.html'}
    ]
  }
}

Этот код позволит обработать переданный файл с учетом всех размеров экранов и инлайнирует весь соответствующий критичный CSS. Это значит, что вы можете просматривать сайт на всех устройствах одинаково быстро. С учетом качества соединения 3G и 4G эта техника очень важна для пользователей мобильных устройств.

Использование Critical на продакшене

Использование инструментов типа Critical это отличный способ автоматического извлечения и инлайнирования критичного CSS, способный изменить ваш подход к разработке сайтов, но как это будет работать в реальных условиях? Чтобы проверить новые файлы в действии, произведите развертывание сайта также как и обычно — вам не надо ничего менять в вашем рабочем окружении. Вам нужно запомнить только то, что вам нужен Grunt каждый раз, когда вы вносите изменения в файлы CSS.

Представленные в статье образцы кода работают с одним файлом CSS, но что делать, если у вас их больше, целый каталог? Ваш Gruntfile можно легко обновить, чтобы он работал со всеми этими файлами:

critical: {
  dist: {
    options: {
      base: './',
      dimensions: [{
        width: 1300,
        height: 900
       },
       {
        width: 500,
        height: 900
      }]
    },
    files: [
      {src: ['index.html'], dest: 'dist/index.html'},
      {src: ['blog.html'], dest: 'dist/blog.html'}
      {src: ['about.html'], dest: 'dist/about.html'}
      {src: ['contact.html'], dest: 'dist/contact.html'}
    ]
  }
}

Вы также можете заставить Grunt обрабатывать каждый файл HTML в нужном каталоге:

critical: {
  dist: {
    options: {
      base: './',
      dimensions: [{
        width: 1300,
        height: 900
      },
      {
        width: 500,
        height: 900
      }],
      src: '*.html',
      dest:  'dist/'
    }
  }
}

Эти образцы помогут вам понять, как использовать Critical на вашем сайте.

Тестирование

Как всегда, важно тестирование всех изменений. Если вы хотите это сделать, к вашим услугам есть несколько волшебных инструментов, доступных бесплатно онлайн. Начните с Google’s PageSpeed Insights, проверив свой URL. Вы заметите, что на странице нет больше блокирующих ресурсов и ваша производительность заметно улучшилась. Возможно, вы знакомы и с инструментом WebPagetest.

WebPagetest

Использование WebPagetest это отличный способ протестировать повременной рендеринг страницы. (Увеличенная версия)

Это бесплатный инструмент, позволяющий вам запустить тест скорости сайта из разных мест со всего мира. Кроме информативного аналитического обзора вашего сайта, там есть инструмент визуальное сравнение, позволяющий сравнивать две страницы друг с другом. Это отличный способ для сравнения результатов до и после обработки критичного CSS.

Идея использования критичного CSS состоит в том, что наши страницы отображаются быстрее, предоставляя часть контента максимально быстро. Измерить эту скорость лучше всего с помощью speed index. Этот замер основано на WebPagetest и показывает, как быстро содержимое вашей страницы визуально заполняется. Speed Index замеряет визуальный прогресс загрузки видимой части страницы и расчитывает в соответствии с этим общий балл. Попробуйте сравнить измерения SpeedIndes до и после инлайнирования критичного CSS. Вы будете впечатлены разницей во времени рендеринга.

Погружаемся глубже

Как и во всех техниках оптимизации у нашего метода есть свои плюсы и минусы. Одним из недостатков инлайнирования критичного CSS является то, что вы не можете кэшировать эти CSS в браузере. Если у вас страницы генерируются динамически и часто меняются, вариант кэширования HTML-страниц вам не подойдет. А значит, инлайнированный CSS будет каждый раз загружаться по новой. Много можно добавить об инлайнировании критичного CSS и об асинхронной загрузке некритичного CSS. Мы всегда можем кэшировать некритичный CSS. в зависимости от вашего подхода можно найти аргументы за и против инлайнирования CSS в <head>. Подробно все это разобрано в статье Ханса Кристиана Рейнля A counter statement: Putting the CSS in the head.

Если вы используете CDN, нужно помнить, что вы по прежнему должны отдавать некритичный CSS с CDN. Это обеспечит доставку ресурсов с наименьшего расстояния и более быструю маршрутизацию, в сравнении с передачей их с основного сервера.

Для традиционных страниц техника инлайнирования подходит лучше, но здесь тоже многое зависит от вашей ситуации. Используете ли вы клиентский JavaScript для генерации HTML? Что делать с одностраничными приложениями (SPA)? Чем раньше вы выведете критичный CSS, тем быстрее страница будет рендерится. Важно понимать, как работает критичный CSS, если вы используете его. Мне импонирует позиция Гая Поджарны по этому поводу:

Несмотря на все ограничения, инлайнирование это по прежнему хороший и важный инструмент в мире фронтенд оптимизации. Таким образом, его стоит использовать, но им не стоит злоупотреблять.

В своей статье “Почему инлайнирование не панацея?”, он дает хорошие рекомендации о том, что нужно и что не нужно делать при инлайнировании CSS.

Метод еще не совершенен

Хотя большинство инструментов, генерирующих и инлайнирующих критичный CSS, постоянно улучшается, еще остались области, которые можно улучшить. Если вы заметите глюки в своем проекте, дайте об этом знать разработчикам.

Оптимизация критического пути рендеринга для вашего сайта может пройти длинный путь в направлении улучшения скорости загрузки. Использование этой техники позволяет использовать отзывчивую раскладку без ущерба. А также это хороший способ обеспечить быструю загрузку, не жертвуя дизайном.

Дополнительные ресурсы

Если вы предпочитаете использовать другую систему сборки типа Gulp, вы можете использовать плагин в ней без установки Grunt. Есть также полезный материал по оптимизации страницы с Gulp.

Также есть другие плагины, извлекающие критичный CSS, например, Penthouse и criticalCSS . Также советую прочитать статью How we make RWD sites load fast as heck от Filament Group, в ней также есть хороший обзор этой техники ускорения загрузки веб-страниц.

Редактор Smashing Magazine, Виталий Фридман написал статью о том, как улучшали производительность на сайте, используя эту технику. Если вы хотите узнать больше о критическом пути рендеринга, есть полезный курс от Udacity. Также есть интересные статьи от Google, особенно в части улучшения передачи CSS. Патрик Хамман написал также написал неплохую статью.

Инлайнируете ли вы критичный CSS по умолчанию? Какие инструменты вы используете? С какими проблемами вы сталкиваетесь? Делитесь мнениями в комментариях к статье.