Рефакторинг CSS: оптимизация размера и производительности (часть 3)
Опубликовано: 2022-03-10В предыдущих статьях этой серии мы рассмотрели аудит работоспособности кодовой базы CSS и стратегию поэтапного рефакторинга CSS, тестирование и обслуживание. Независимо от того, насколько кодовая база CSS была улучшена в процессе рефакторинга и насколько она более удобна в сопровождении и расширении, окончательная таблица стилей должна быть оптимизирована для обеспечения наилучшей производительности и минимально возможного размера файла.
Развертывание переработанной кодовой базы не должно приводить к ухудшению производительности веб-сайта и ухудшению взаимодействия с пользователем. В конце концов, пользователи не будут вечно ждать загрузки сайта. Кроме того, руководство будет недовольно снижением трафика и доходов из-за неоптимизированной кодовой базы, несмотря на улучшение качества кода.
В этой статье мы рассмотрим стратегии оптимизации CSS, которые могут оптимизировать размер файла CSS, время загрузки и производительность рендеринга. Таким образом, рефакторинговая кодовая база CSS становится не только более удобной в сопровождении и расширяемой, но и более производительной и удовлетворяет всем требованиям, важным как для конечного пользователя, так и для руководства.
Часть: Рефакторинг CSS
- Часть 1: Рефакторинг CSS: Введение
- Часть 2: CSS-стратегия, регрессионное тестирование и сопровождение
- Часть 3: Оптимизация размера и производительности
- Подпишитесь на нашу электронную рассылку, чтобы не пропустить следующие.
Оптимизация размера файла таблицы стилей
Оптимизация размера файла сводится к удалению ненужных символов и форматированию, а также к оптимизации кода CSS для использования другого синтаксиса или сокращенных свойств для уменьшения общего количества символов в файле.
Оптимизация и минификация
Оптимизация и минимизация CSS существуют уже много лет и стали одним из основных элементов оптимизации внешнего интерфейса. Такие инструменты, как cssnano и clean-css, являются одними из моих любимых инструментов, когда речь идет об оптимизации и минимизации CSS. Они предлагают широкий спектр параметров настройки для дальнейшего контроля оптимизации кода и поддерживаемых браузеров.
Эти инструменты работают по схожему принципу. Сначала неоптимизированный код анализируется и транспилируется по правилам, установленным в конфиге. В результате код использует меньше символов , но сохраняет форматирование (разрывы строк и пробелы).
/* Before - original and unoptimized code */ .container { padding: 24px 16px 24px 16px; background: #222222; } /* After - optimized code with formatting */ .container { padding: 24px 16px; background: #222; }
И, наконец, транспилированный оптимизированный код минимизируется за счет удаления всего ненужного форматирования текста . В зависимости от кодовой базы и поддерживаемых браузеров, установленных в конфигурации, код с устаревшими префиксами поставщиков также может быть удален.
/* Before - optimized code with formatting */ .container { padding: 24px 16px; background: #222; } /* After - optimized and minified code */ .container{padding:24px 16px;background:#222}
Даже в этом базовом примере нам удалось уменьшить общий размер файла с 76 байт до 55 байт, что привело к уменьшению на 23%. В зависимости от кодовой базы, инструментов оптимизации и конфигурации оптимизация и минимизация CSS могут быть еще более эффективными.
Оптимизацию и минимизацию CSS можно считать легкой победой из-за значительной отдачи всего за несколько настроек рабочего процесса CSS. Вот почему минимизацию следует рассматривать как минимальную оптимизацию производительности и требование для всех таблиц стилей в проекте.
Оптимизация медиазапросов
Когда мы пишем медиа-запросы в CSS, особенно при использовании нескольких файлов (PostCSS или Sass), мы обычно не вкладываем код в один медиа-запрос для всего проекта. Для улучшения ремонтопригодности, модульности и структуры кода мы обычно пишем одни и те же выражения медиа-запросов для нескольких компонентов CSS.
Давайте рассмотрим следующий пример неоптимизированной кодовой базы CSS.
.page { display: grid; grid-gap: 16px; } @media (min-width: 768px) { .page { grid-template-columns: 268px auto; grid-gap: 24px; } } /* ... */ .products-grid { display: grid; grid-template-columns: repeat(2, 1fr); grid-gap: 16px; } @media (min-width: 768px) { .products-grid { grid-template-columns: repeat(3, 1fr); grid-gap: 20px; } }
Как видите, у нас есть повторяющиеся @media (min-width: 768px)
для каждого компонента для лучшей читабельности и обслуживания. Давайте запустим оптимизацию и минимизацию на этом примере кода и посмотрим, что мы получим.
.page{display:grid;grid-gap:16px}@media (min-width: 768px){.page{grid-template-columns:268px auto;grid-gap:24px}}.products-grid{display:grid;grid-template-columns:repeat(2,1fr);grid-gap:16px}@media (min-width: 768px){.products-grid{grid-template-columns:repeat(3,1fr);grid-gap:20px}}
Это может быть немного сложно читать, но все, что мы должны заметить, — это повторяющийся медиа-запрос @media (min-width: 768px)
. Мы уже пришли к выводу, что хотим уменьшить количество символов в таблице стилей и можем вкладывать несколько селекторов в один медиа-запрос, так почему же минификатор не удалил повторяющееся выражение? Тому есть простая причина.
Порядок правил имеет значение в CSS, поэтому для объединения дублированных медиазапросов необходимо переместить блоки кода. Это приведет к изменению порядка правил, что может вызвать нежелательные побочные эффекты в стилях.
Однако объединение медиа-запросов потенциально может сделать размер файла еще меньше, в зависимости от кодовой базы и структуры. Инструменты и пакеты, такие как postcss-sort-media-queries, позволяют нам удалять повторяющиеся медиа-запросы и дополнительно уменьшать размер файла.
Конечно, важно иметь хорошо структурированную структуру кодовой базы CSS , которая не зависит от порядка правил. Эту оптимизацию следует учитывать при планировании рефакторинга CSS и установлении основных правил.
Я бы рекомендовал сначала проверить, перевешивает ли выгода от оптимизации потенциальные риски. Это можно легко сделать, запустив аудит CSS и проверив статистику медиа-запросов. Если это так, я бы рекомендовал добавить его позже и запустить автоматическое регрессионное тестирование, чтобы выявить любые неожиданные побочные эффекты и ошибки, которые могут возникнуть в результате.
Удаление неиспользуемого CSS
В процессе рефакторинга всегда есть вероятность того, что в конечном итоге вы окажетесь с некоторыми неиспользуемыми устаревшими стилями , которые не были полностью удалены, или у вас будут некоторые недавно добавленные стили, которые не используются. Эти стили также увеличивают общее количество символов и размер файла. Однако устранение этих неиспользуемых стилей с помощью автоматизированных инструментов может быть несколько рискованным, поскольку эти инструменты не могут точно предсказать, какие стили используются на самом деле.
Такие инструменты, как purgecss, просматривают все файлы в проекте и используют все классы, упомянутые в файлах, в качестве селекторов, просто чтобы быть осторожным и случайно не удалить селекторы для динамических элементов, внедренных JavaScript, среди других потенциальных случаев. Однако purgecss предлагает гибкие параметры конфигурации в качестве обходного пути для этих потенциальных проблем и рисков.
Однако это улучшение следует проводить только тогда, когда потенциальные выгоды перевешивают риски . Кроме того, этот метод оптимизации потребует значительного времени для настройки, настройки и тестирования и может вызвать непреднамеренные проблемы в будущем, поэтому действуйте с осторожностью и убедитесь, что установка является надежной.
Устранение блокировки рендеринга CSS
По умолчанию CSS является ресурсом, блокирующим рендеринг, что означает, что веб-сайт не будет отображаться для пользователя до тех пор, пока все связанные таблицы стилей и их зависимости (например, шрифты) не будут загружены и проанализированы браузером.

Если файл таблицы стилей имеет большой размер или несколько зависимостей, расположенных на сторонних серверах или CDN, рендеринг веб-сайта может значительно задерживаться в зависимости от скорости и надежности сети.
Крупнейший Contentful Paint (LCP) стал важной метрикой за последние несколько месяцев. LCP важен не только для производительности, но и для SEO — веб-сайты с лучшими показателями LCP будут иметь более высокий рейтинг в результатах поиска. Удаление ресурсов, блокирующих рендеринг, таких как CSS, — это один из способов улучшить оценку LCP.
Однако, если бы мы отложили загрузку и обработку таблицы стилей, это привело бы к Flash Of Unstyled Content (FOUC) — содержимое было бы отображено пользователю сразу, а стили были бы загружены и применены через несколько секунд. Этот переключатель может показаться неприятным и может даже сбить с толку некоторых пользователей.
Критический CSS
С помощью Critical CSS мы можем гарантировать, что веб- сайт загружается с минимальным количеством стилей , которые гарантированно будут использоваться на странице при ее первоначальном отображении. Таким образом, мы можем сделать FOUC намного менее заметным или даже устранить его в большинстве случаев. Например, если на главной странице есть компонент заголовка с навигацией и главный компонент, расположенный в верхней части страницы, это означает, что критический CSS будет содержать все необходимые глобальные стили и стили компонентов для этих компонентов, а стили для других компонентов на странице будет отложено.
Этот CSS встроен в HTML под тегом style
, поэтому стили загружаются и анализируются вместе с файлом HTML. Хотя это приведет к немного большему размеру файла HTML (который также должен быть минимизирован), все остальные некритические CSS будут отложены и не будут загружены сразу, а веб-сайт будет отображаться быстрее. В целом, преимущества перевешивают увеличение размера файла HTML.
<head> <style type="text/css"><!-- Minified Critical CSS markup --></style> </head>
Существует множество автоматизированных инструментов и пакетов NPM, в зависимости от ваших настроек, которые могут извлекать важные CSS и генерировать отложенные таблицы стилей.
Откладывание таблиц стилей
Как именно мы делаем CSS неблокирующим? Мы знаем, что на него не следует ссылаться в элементе head
HTML при первой загрузке HTML страницы. Демиан Ренцулли описал этот метод в своей статье.
Не существует нативного HTML-подхода (пока) для оптимизации или отсрочки загрузки ресурсов, блокирующих рендеринг, поэтому нам нужно использовать JavaScript для вставки некритической таблицы стилей в HTML-разметку после начального рендеринга. Мы также должны убедиться, что эти стили загружаются неоптимальным (блокирующим рендеринг) способом, если пользователь посещает страницу с отключенным JavaScript в браузере.
<!-- Deferred stylesheet --> <link rel="preload" as="style" href="path/to/stylesheet.css" onload="this.onload=null;this.rel='stylesheet'"> <!-- Fallback --> <noscript> <link rel="stylesheet" href="path/to/stylesheet.css"> </noscript>
С помощью link rel="preload" as="style"
файл таблицы стилей запрашивается асинхронно, а обработчик onload
JavaScript гарантирует, что файл загружается и обрабатывается браузером после завершения загрузки HTML-документа. Требуется некоторая очистка, поэтому нам нужно установить для onload
значение null
, чтобы эта функция не запускалась несколько раз и не вызывала ненужных повторных рендерингов.

Именно так Smashing Magazine обрабатывает свои таблицы стилей. Каждый шаблон (домашняя страница, категории статей, страницы статей и т. д.) имеет специфический для шаблона критический CSS , встроенный в тег style
HTML в элементе head
, и отложенную таблицу стилей main.css
, которая содержит все некритические стили.
Однако вместо переключения параметра rel
здесь мы видим, как медиа-запрос переключается с автоматически отложенного низкоприоритетного print
носителя на высокоприоритетный атрибут all
после завершения загрузки страницы. Это альтернативный, столь же жизнеспособный подход к отсрочке загрузки некритичных таблиц стилей.
<link href="/css/main.css" media="print" onload="this.media='all'" rel="stylesheet">
Разделение и условная загрузка таблиц стилей с помощью медиа-запросов
В случаях, когда окончательный файл таблицы стилей имеет большой размер файла даже после применения вышеупомянутых оптимизаций, вы можете разделить таблицы стилей на несколько файлов на основе медиа-запросов и использовать свойство media в таблицах стилей, на которые ссылается HTML-элемент ссылки, для их условной загрузки. .
<link href="print.css" rel="stylesheet" media="print"> <link href="mobile.css" rel="stylesheet" media="all"> <link href="tablet.css" rel="stylesheet" media="screen and (min-width: 768px)"> <link href="desktop.css" rel="stylesheet" media="screen and (min-width: 1366px)">
Таким образом, если используется подход, ориентированный на мобильные устройства, стили для больших размеров экрана не будут загружаться или анализироваться на мобильных устройствах, которые могут работать в более медленных или ненадежных сетях.
Еще раз повторюсь, этот метод следует использовать, если в результате применения ранее упомянутых методов оптимизации получается таблица стилей с неоптимальным размером файла. В обычных случаях этот метод оптимизации будет не таким эффективным или действенным, в зависимости от размера отдельной таблицы стилей.
Откладывание файлов шрифтов и таблиц стилей
Откладывание таблиц стилей шрифтов (например, файлов шрифтов Google) также может быть полезно для начальной производительности рендеринга. Мы пришли к выводу, что таблицы стилей блокируют рендеринг, как и файлы шрифтов, на которые есть ссылки в таблице стилей. Файлы шрифтов также значительно увеличивают начальную производительность рендеринга.
Загрузка таблиц стилей шрифтов и файлов шрифтов — сложная тема, и ее подробное изучение потребовало бы целой новой статьи только для того, чтобы объяснить все жизнеспособные подходы. К счастью, Зак Лезерман изложил множество жизнеспособных стратегий в этом замечательном исчерпывающем руководстве и резюмировал плюсы и минусы каждого подхода. Если вы используете Google Fonts, Гарри Робертс изложил стратегию максимально быстрой загрузки Google Fonts.
Если вы решите отложить таблицы стилей шрифтов, вы получите Flash of Unstyled Text (FOUT). Первоначально страница будет отображаться с резервным шрифтом до тех пор, пока файлы отложенных шрифтов и таблицы стилей не будут загружены и проанализированы, после чего будут применены новые стили. Это изменение может быть очень заметным и может привести к смещению макета и сбить пользователей с толку, в зависимости от конкретного случая.
Барри Поллард обрисовал некоторые стратегии, которые могут помочь нам справиться с FOUT, и рассказал о предстоящей функции CSS для настройки размера, которая обеспечит более простой и естественный способ работы с FOUT.
Оптимизация на стороне сервера
HTTP-сжатие
В дополнение к минимизации и оптимизации размера файла для дополнительного уменьшения размера загружаемого файла можно использовать статические ресурсы, такие как HTML, файлы CSS, файлы JavaScript и т. д. Алгоритмы сжатия HTTP, такие как Gzip и Brotli.
Сжатие HTTP необходимо настроить на сервере, что зависит от технического стека и конфигурации. Однако преимущества производительности могут различаться и могут не иметь такого большого влияния, как минимизация и оптимизация стандартной таблицы стилей, поскольку браузеры все равно будут распаковывать сжатые файлы и должны их анализировать.
Кэширование таблиц стилей
Кэширование статических файлов — полезная стратегия оптимизации. Браузеры по-прежнему будут загружать статические файлы с сервера при первой загрузке, но как только они будут кэшированы, они будут загружаться с него непосредственно при последующих запросах, что ускоряет процесс загрузки.
Кэшированием можно управлять через HTTP-заголовок Cache-Control на уровне сервера (например, с помощью файла .htaccess
на сервере Apache).
С помощью max-age
мы можем указать, как долго файл должен оставаться в кэше (в секундах) в браузере, а с помощью public
мы указываем, что файл может кэшироваться браузером и любыми другими кэшами.
Cache-Control: public, max-age=604800
Более агрессивная и эффективная стратегия кэширования статических ресурсов может быть достигнута с помощью immutable
конфигурации. Это сообщает браузеру, что этот конкретный файл никогда не изменится и что любые новые обновления приведут к удалению этого файла, а его место займет новый файл с другим именем. Это известно как очистка кеша .
Cache-Control: public, max-age=604800, immutable
Без надлежащей стратегии очистки кеша существует риск потери контроля над файлами, кэшируемыми в браузере пользователя. Это означает, что если файл изменится, браузер не сможет узнать, что он должен загрузить обновленный файл и не использовать устаревший кешированный файл. И с этого момента мы практически ничего не можем сделать, чтобы это исправить, и пользователь останется с устаревшим файлом до истечения срока его действия.
Для таблиц стилей это может означать, что если бы мы обновили HTML-файлы с новым содержимым и компонентами, требующими нового стиля, эти стили не будут отображаться, потому что устаревшая таблица стилей кэшируется без стратегии очистки кеша, и браузер не узнает об этом. он должен загрузить новый файл.
Прежде чем использовать стратегию кэширования для таблиц стилей или любых других статических файлов, следует реализовать эффективные механизмы очистки кеша, чтобы предотвратить застревание устаревших статических файлов в кеше пользователя. Вы можете использовать один из следующих механизмов управления версиями для очистки кеша:
- Добавление строки запроса к имени файла.
Напримерstyles.css?v=1.0.1.
Однако некоторые CDN могут полностью игнорировать или удалять строку запроса из имени файла, что приводит к тому, что файл застревает в кеше пользователя и никогда не обновляется. - Изменение имени файла или добавление хэша.
Напримерstyles.a1bc2.css
илиstyles.v1.0.1.css.
Это более надежно и эффективно, чем добавление строки запроса к имени файла.
CDN или собственный хостинг?
Сеть доставки контента (CDN) — это группа географически распределенных серверов, которые обычно используются для надежной и быстрой доставки статических ресурсов, таких как изображения, видео, файлы HTML, файлы CSS, файлы JavaScript и т. д.
Хотя CDN могут показаться отличной альтернативой самостоятельному размещению статических ресурсов, Гарри Робертс провел углубленное исследование по этой теме и пришел к выводу, что самостоятельно размещаемые ресурсы более выгодны для производительности.
«На самом деле очень мало причин оставлять свои статические активы в чьей-либо инфраструктуре. Воспринимаемые преимущества часто являются мифом, и даже если бы это было не так, компромиссы просто того не стоят. Загрузка ресурсов из нескольких источников заметно медленнее».
При этом я бы рекомендовал самостоятельно размещать таблицы стилей (включая таблицы стилей шрифтов, если это возможно) по умолчанию и переходить на CDN только в том случае, если для этого есть веские причины или другие преимущества.
Аудит размера и производительности файла CSS
WebPageTest и другие подобные инструменты аудита производительности можно использовать для получения подробного обзора процесса загрузки веб-сайта, размеров файлов, ресурсов блокировки рендеринга и т. д. Эти инструменты могут дать вам представление о том, как ваш веб-сайт загружается на самых разных устройствах — от настольного ПК, работающего в высокоскоростной сети, до недорогих смартфонов, работающих в медленных и ненадежных сетях.
Давайте проведем аудит производительности на веб-сайте, упомянутом в первой статье из этой серии — на том, который имеет 2 МБ минимизированного CSS.
Во-первых, мы рассмотрим разбивку контента , чтобы определить, какие ресурсы занимают наибольшую пропускную способность. Из следующих диаграмм видно, что изображения занимают больше всего запросов, а это означает, что их нужно загружать отложенно. Из второй диаграммы видно, что таблицы стилей и файлы JavaScript являются самыми большими с точки зрения размера файла. Это хороший показатель того, что эти файлы необходимо либо минимизировать и оптимизировать, либо подвергнуть рефакторингу, либо разделить на несколько файлов и загрузить асинхронно.

Мы можем сделать еще больше выводов из диаграмм Web Vitals. Взглянув на диаграмму Largest Contentful Paint (LCP), мы можем получить подробный обзор ресурсов, блокирующих рендеринг, и того, насколько они влияют на первоначальный рендеринг.
Мы уже могли сделать вывод, что таблица стилей веб-сайта окажет наибольшее влияние на LCP и статистику загрузки. Однако мы можем видеть таблицы стилей шрифтов, файлы JavaScript и изображения, на которые есть ссылки внутри таблиц стилей, которые также блокируют рендеринг. Зная, что мы можем применить вышеупомянутые методы оптимизации, чтобы сократить время LCP за счет устранения ресурсов, блокирующих рендеринг.

Заключение
Процесс рефакторинга не завершен, когда работоспособность и качество кода улучшены, а слабые места и проблемы в кодовой базе устранены. Рефакторинг кодовой базы должен привести к такой же или улучшенной производительности по сравнению с устаревшей кодовой базой.
Конечные пользователи не должны сталкиваться с проблемами производительности или длительной загрузкой обновленной кодовой базы. К счастью, существует множество способов убедиться, что кодовые базы являются надежными и производительными — от простых методов минимизации и оптимизации до более сложных методов, таких как устранение ресурсов, блокирующих рендеринг, и разделение кода.
Мы можем использовать различные инструменты аудита производительности, такие как WebPageTest , чтобы получить подробный обзор времени загрузки, производительности, ресурсов, блокирующих рендеринг, и других факторов, чтобы мы могли решить эти проблемы на ранней стадии и эффективно.
Часть: Рефакторинг CSS
- Часть 1: Рефакторинг CSS: Введение
- Часть 2: Рефакторинг CSS: стратегия, регрессионное тестирование и сопровождение
- Часть 3: Рефакторинг CSS: оптимизация размера и производительности
- Подпишитесь на нашу электронную рассылку, чтобы не пропустить следующие.
использованная литература
- «Render Blocking CSS», Илья Григорик
- «Отложите некритичный CSS», Демиан Ренцулли
- «Полное руководство по стратегиям загрузки шрифтов», Зак Лезерман
- «Новый способ уменьшить влияние загрузки шрифта: дескрипторы шрифтов CSS», Барри Поллард.
- «Самостоятельное размещение ваших статических ресурсов», Гарри Робертс
- «Оптимизируйте загрузку и отрисовку WebFont», Илья Григорик