Я довольно долго ходил взад и вперед по Tailwind CSS. С одной стороны, мне нравился дизайн, ориентированный на полезность, с другой — я ненавидел то, как мои HTML, JSX и т. д. раздувались из-за количества имен классов, необходимых для стилизации даже простой кнопки.

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

Кроме того, после более чем года использования Tailwind для различных проектов я обнаружил, что это повысило мою продуктивность. В сочетании с служебными классами фреймворка, основанными на компонентах, они работают очень хорошо, особенно если вы уже запомнили их все. Хотя есть одно предостережение…

Состав класса

Составлять служебные классы Tailwind сложно.

Представьте, что вы создаете целый пользовательский интерфейс с базовыми компонентами, стили которых уже определены с помощью набора классов Tailwind. Что происходит, когда вы хотите немного изменить компонент только для одного варианта использования? Вы не можете применить m-0 класс, потому что m-1, который компонент уже применил, имеет более высокую специфичность.

Существует много мнений о том, как поступать в таких случаях. Некоторые рекомендуют использовать директиву @apply для базовых стилей ваших компонентов. Другие утверждают, что вы уже должны рассмотреть все возможные варианты вашего компонента и использовать логику JavaScript для применения правильных классов на основе, например. на свойствах компонента.

Для меня оба эти решения кажутся компромиссами. Я не люблю использовать @apply без крайней необходимости. С другой стороны, продумывание всех вариантов заранее или включение их всех в базовый компонент либо ограничивает ваши проекты, либо приводит к чрезмерному использованию JS на стороне клиента.

Однако есть несколько сторонних решений этой проблемы.

Существующие альтернативы

Дело в том, что почти все существующие решения предполагают использование JS на стороне клиента. Таким образом, хотя они более удобны для разработчиков, чем, например. объединяя служебные классы вручную, они излишне замедляют работу вашего веб-сайта.

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

твин.макро

Одной из наиболее многообещающих альтернатив является twin.macroмакрос Babel, который обрабатывает классы Tailwind для создания объектов JS, понятных различным библиотекам CSS-in-JS. Опыт разработчика (DX) при его использовании просто потрясающий, поскольку вы не только получаете все функции Tailwind без особых изменений в коде, но и получаете гораздо большую гибкость — и все это в дополнение к традиционным преимуществам CSS-in-JS. Вот пример кода:

Проблема в том, что twin.macro, выполняя некоторую обработку во время сборки, по-прежнему добавляет много JS на стороне клиента — как за счет использования движка CSS-in-JS, так и за счет помещения всех объектов стилей, созданных с помощью макроса, в ваш JS-код. Это означает не только более низкую производительность, но и большие размеры пакетов.

В то время как twin.macro обеспечил лучший DX на сегодняшний день, есть пара других альтернатив, которые приблизились к нему, не добавляя столько дополнительного JS-кода.

Экстракт ванили

Ванильный экстракт позволяет использовать TypeScript в качестве препроцессора CSS, как и Sass. Кроме того, он поставляется с Sprinkles — атомарной структурой CSS, которая позволяет вам воспроизводить служебные классы Tailwind.

Таблицы стилей TS должны быть определены в отдельных файлах .css.js или .css.ts, хотя для использования «нулевого времени выполнения». С учетом сказанного, чтобы добиться действительно нулевого использования времени выполнения, вы можете использовать Sprinkles только в других таблицах стилей TS. Это несколько ограничивает вашу гибкость.

Хотя вы можете использовать Sprinkles непосредственно в коде JS/TS, потребуется небольшое время выполнения — вспомогательная функция и объект сопоставления, содержащий все ваши атомарные классы, необходимые для поиска классов во время выполнения.

Если вы хотите воспроизвести весь набор служебных классов из Tailwind, этот объект будет огромным.

Винди CSS

Windi CSS — это прямая альтернатива Tailwind (с полной функциональной совместимостью с Tailwind CSS v2), с более простой настройкой и более быстрым временем компиляции. Хотя преимущества этого фреймворка уменьшились по мере того, как Tailwind дорос до версии 3, его наиболее многообещающей функцией (с точки зрения состава классов) был режим компиляции. Он предназначался для компиляции служебных классов, применяемых к элементам, в отдельные классы с ограниченной областью действия.

При правильной реализации этот подход может решить все проблемы, связанные с составом классов, при этом предоставляя DX, аналогичный тому, что используется в Tailwind. Единственным недостатком будет то, что, как описано, это будет комплексное решение, которое не позволяет вам выбирать, какие служебные классы «компилировать», а какие оставить как есть, что может привести к большому размеру CSS. связки.

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

Решение с нулевым временем выполнения

Изучив все вышеперечисленные альтернативы (и многое другое), я решил реализовать свое собственное решение. Для этого я обратился к Linaria — настоящей библиотеке CSS-in-JS с нулевым временем выполнения.

После того, как Linaria выполнит свою обработку на этапе сборки, все, что вы получите, — это просто строка в JS, в то время как фактический стиль извлекается в специальный файл CSS. Кроме того, он хорошо интегрируется с большинством препроцессоров, таких как Sass или PostCSS, вместе с плагином PostCSS Tailwind.

Благодаря этому, используя Linaria, я смог получить что-то вроде следующего:

С Linaria и JSX я получил весь свой компонент, включая стили и структуру, в одном файле, не жертвуя при этом производительностью или качеством кода. Единственная проблема осталась с синтаксисом.

Хотя это и не слишком долго, css`@apply нужно много раз повторять для каждого класса, который вы хотите скомпилировать. Вот почему, используя Vite и некоторые плагины Rollup (Vite использует Rollup под капотом), я смог сократить его до этого:

Без необходимости в каком-либо дополнительном импорте и синтаксисе литерального тега шаблона tw (вдохновленном twin.macro), это стало моим решением для всех проектов, использующих Tailwind.

Подводя итог преимуществам этого решения по сравнению с предыдущими альтернативами:

  • Необязательное название класса «компиляция»;
  • Действительно нулевое время выполнения (только строки);
  • Все еще использую Tailwind под капотом (со всеми его служебными классами и доступом к последним обновлениям);
  • Отличный DX (компактный синтаксис, автозаполнение в VS Code просто путем настройки регулярного выражения в расширении Tailwind);

Но есть один недостаток — настройка. Linaria, потрясающая своей функциональностью, оказывается довольно проблематичной в установке, даже с имеющимися руководствами и интеграциями. Я почти всегда сталкивался с проблемами при настройке в новом проекте. Кроме того, если вам нужен сокращенный синтаксис на основе tw, вам также потребуется дополнительная настройка:

Приведенная выше конфигурация — это то, что я использовал, чтобы стенография и Liniaria работали в Vite. Чтобы дать вам общее представление о том, как это работает — литеральный тег шаблона tw\`` is first replaced with css`@applyand then thecss` автоматически импортируется там, где это необходимо. Я использовал эту настройку только с Vite и Astro (на основе Vite), поэтому я не знаю, насколько сложно будет заставить ее работать в других сборщиках (хотя чистый Rollup тоже должен работать).

Из-за такой сложной настройки и всех возможных исправлений ошибок я бы не рекомендовал это всем. С учетом сказанного, я готов пройти через это, просто чтобы позже насладиться хорошим DX, эффективным стилем и простым составом классов. Я еще не исследовал извлечение всей настройки в отдельный плагин Vite, но, возможно, стоит подумать об этом.

UnoCSS — новейшая альтернатива

Теперь я хотел бы упомянуть еще одну альтернативу Tailwind, которая может заслуживать вашего внимания — особенно в отношении состава классов — UnoCSS.

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

Лучшее в UnoCSS то, что он выглядит как лучший инструмент для атомарного CSS, с различными предустановками для определения служебных классов (включая один для Tailwind CSS) и отличными функциями, которых нет в Tailwind, включая компиляцию режим!

Правильно, в UnoCSS есть режим компиляции, который даже лучше, чем тот, который изначально предназначался для Windi CSS, так как он опциональный (с настраиваемым префиксом), что означает, что вы компилируете только те имена классов, которые хотите!

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

Заключение

Этот пост — результат года или двух исследований, экспериментов и фактического использования различных инструментов в различных моих проектах. Он даже не охватил все альтернативы, которые я тестировал, и то, что возможно с такими, как UnoCSS и другими «передовыми» решениями. С учетом сказанного, если вы имеете дело с составом классов и ищете отличный опыт разработки, я надеюсь, что эта статья оказалась вам полезной!

Пишите

Ведение блога для разработчиков | выходит в 2023 г.
Присоединяйтесь к списку ожидания прямо сейчас 👉 https://vrite.io

Профессиональный редактор и мощная безголовая CMS в одном. Vrite — это платформа для письма, созданная разработчиками для разработчиков.