Адам Ватан на днях поделился новостью, что Shopify выкупил Tailwind. На DotDev 2026, конференции, организованной Shopify, был анонс внедрение Tailwind в движок Shopify Storefront Renderer. В связи с этим обзор подходов к стилям в Shopify.
Вопрос организации стилей в темах Shopify лежит на плечах авторов тем. Тут каждый сам решает, как к этому подойти. Поэтому можно найти разные решения. В рамках этого поста я сосредоточусь на решениях в официальных темах от Shopify.
Тема Debut, 2016-2021 годы. Все стили находятся в файле
theme.scss.liquid, где примерно 5700 строк кода. Файл содержит стили normalize.css, карусели slick, системы сетки, разных компонентов и шаблонов страниц самой темы.Файл представлен как
.liquid, то есть там доступны ограниченные возможности шаблонизатора Liquid. Это используется для получения различных настроек из админкм и подстановки в переменные для дальнейшего использования в стилях.Сами стили написаны в синтаксисе SCSS, что отражено в виде расширения
.scss. Бэкенд Shopify компилирует Liquid в SCSS, а затем SCSS в CSS по запросу. В коде много SCSS-переменных, миксинов, функций и кое где используется вложенность.У подхода две проблемы:
- Время компиляции откладывает загрузку страницы и TTFB, особенно при больших размерах файла и при большом количестве SCSS-фич;
- Большой файл стилей откладывает отрисовку до тех пор, пока не будет полностью загружен и обработан.
Тема Dawn, 2021-2025 годы. От компиляции Liquid и SCSS отказались. Стили находятся в файлах
.css или встроены в <style>, где требуется кастомизация. На страницу подключается набор базовых стилей и стили используемых секций.<head>
<!-- Базовые стили подключаются на всех страницах -->
<link
rel="stylesheet"
href="//shop.myshopify.com/cdn/.../base.css"
>
<!-- ... -->
</head>
<body>
<header class="section-header">
<style>
/*
Некоторые критические стили
шапки для быстрой отрисовки
*/
</style>
<!--
Менее критические стили, которые
не нужны сразу, загружаются лениво
-->
<link
rel="stylesheet"
href="//shop.myshopify.com/cdn/.../component-search.css"
media="print"
onload="this.media='all'"
>
</header>
<section
id="...__imge-banner"
class="shopify-section section"
>
<!--
Стили секции подключаются
перед контентом самой секций
-->
<link
rel="stylesheet"
href="//shop.myshopify.com/cdn/.../section-image-banner.css"
media="all"
>
<!-- Контент секции -->
</section>
<!-- Аналогично в других секциях -->
</body>
Применяется сразу несколько техник загрузки стилей. Первая —
<link> в <body>. Хотя <link> обычно находится в <head>, размещение в <body> даёт эффект последовательной отрисовки и улучшает показатель FCP за счёт уменьшения блокировок.Вторая техника — отложенная загрузка. С атрибутом
media="print" стили загружаются с пониженным приоритетом и не блокируют отрисовку. Когда они загрузятся, срабатывает обработчик onload и меняет print на all. После этого стили применяются.Чтобы не ломать страницу, можно добавить резервный вариант внутри
<noscript> без media="print" и обработчика onload. Если JS по каким-то причинам будет недоступен, стили загрузятся обычным способом.Однако такая организация стилей требует грамотного разделения стилей, знания используемых техник и дополнительного менеджмента со стороны разработчика. В разметке много элементов
<link>, которые провоцируют множество запросов.Тема Horizon, 2025-2026 годы. Новая флагманская тема Horizon пришла на смену Dawn с архитектурой блоков. Это независимые компоненты с настройками в админке, которые могут вставляться в секции на любой странице и друг в друга.
Это потребовало изменений в организации стилей. При старом подходе это означало бы десятки элементов
<link> в <body> и много запросов за небольшими файлами стилей. Это работоспособно, но не очень удобно и засоряет разметку.Стили размещаются в Liquid-тэге
stylesheet внутри файла секций и блоков. Это похоже на организацию Single File Component во Vue, когда стили колоцированы в одном файле вместе с шаблоном и логикой.<div class="block-heading">
<!-- Шаблон блока -->
</div>
{% stylesheet %}
/* Стили блока */
{% endstylesheet %}
{% schema %}
// Настройки блока
{% endschema %}
Стили извлекаются из тэгов
stylesheet у всех секций и блоков и объединяются в один бандл compiled_assets/styles.css. Это шаг назад к одному большому CSS-файлу времён Debut, но теперь он генерируется автоматически.Позже тэг
stylesheet был доработан так, чтобы для каждой страницы извлекались стили только используемых на ней секций и блоков. В теории это должно было давать бандл под каждую страницу, чего на практике не происходит.Другая причина внедрения
stylesheet — развитие агентской разработки. Агентам проще работать и сохранять контекст в рамках одного файла. Колокация шаблона и стилей этому способствует, а также уменьшает потребление токенов.В Horizon сохраняется файл с базовыми стилями
base.css и некоторое количество встроенных в <style> стилей. Что в Dawn, что в Horizon стили написаны достаточно сложно и запутано (во многом благодаря применению ИИ при разработке).В стилях отсутствует системный подход, много сложных селекторов с комбинаторами и высокой специфичностью, связанные стили могут находится в разных файлах, много переопределений. Всё это усложняет кастомизацию и поддержку.
Также агентам сложно работать с такой кодовой базой не смотря на набор скиллов от разработчиков темы. В ответ на все эти вызовы Shopify объявил о внедрении поддержки Tailwind, а теперь и новость о приобретении Tailwind.
То есть вместо создания CSS-файлов, использования тэгов
stylesheet и выстраивания системы, в шаблонах Liquid будут доступны классы Tailwind. Бэкенд Shopify будет анализировать шаблон и генерировать итоговый CSS-файл из Tailwind-классов.При всей моей нелюбви к Tailwind, выбор Shopify в пользу Tailwind понятен. Бандл будет минимальным, агентам будут проще работать, разработчикам не нужно будет думать про организацию стилей, отдельные файлы, именование и специальные тэги.
Пока это планы, реализации нет. Но всё равно интересно проследить эволюцию и увидеть, как в итоге всё больше приходят к Tailwind. Я со своими предпочтениями к ванильному CSS немного грущу, но что уж тут поделать.
#css