
Привет, Хабр! Меня зовут Александр Водолазских. Я живу в Новосибирске и я работаю Frontend Domain Lead в СберМаркете. Сегодня хочу немного поговорить об опыте работы с Tailwind CSS — utility-first CSS framework. Поделюсь болью и радостью, которые возникли при его эксплуатации.
Библиотека Tailwind довольно молодая, первые бета-версии появились в 2017 году. Но по количеству звёзд и форков можно понять, что комьюнити вокруг сложилось солидное. Инструмент предоставляет нам большой набор готовых классов и утилит, которые облегчают и ускоряют стилизацию приложения/сайта. Вы просто пишете короткие имена заранее спроектированных классов: цвета, отступы, позиционирование. Хватает классов и для сайзинга, типографики, анимации бэкграундов и многого другого.
Ниже можно увидеть, как всё это выглядит при реализации на React JS.

Радует и совместимость: всё спокойно собирается и под Next.js, и под Vite, и под Angular, и под Create React App. Более того, есть возможность сборки с помощью PostCSS-плагина, что делает инструмент поистине хорошо имплементируемым в любой системе.

Но есть у Tailwind и недостатки. На самом деле это довольно холиварный инструмент.
Допустим, у вас стартап…
Представим, вы с друзьями решили сделать стартап: арендовали гараж для работы, собрали лучшую команду и подобрали крутой технологический стек. Что касается CSS — вы решили найти модное решение для стилизации, и глаз упал на Tailwind. Всем нравится, коллеги довольны, и ничто не предвещает беды.
Вдруг команда получает деньги от инвестора и уже собирается пилить новые бизнес-фичи, но сталкивается с тем, что для комфортного сожительства с Tailwind его нужно «привести в порядок», иначе всё дальнейшее масштабирование под угрозой. И вообще, поддерживать разросшиеся стили становится трудновато, разработчики каждое утро вытирают скупые слёзы левым рукавом.
Почему масштабировать и поддерживать модное решение для стилизации оказывается грустно:
-
Фреймворк неинформативен. Понятных названий классов в нём просто нет, а как навигироваться в DOM-дереве при дебаге — вообще не понятно.
-
Классов очень много, их попросту сложно запомнить, особенно вновь прибывающим молодым разрабам. Мы же растём, помните?
-
Появляются многострочные портянки из классов.
-
Неясно, каким образом привести груду написанных стилей в общую систему и избавиться от тотального бардака.
Болей достаточно много, как говорится: «Есть от чего впасть в отчаяние». Хорошая новость состоит в том, что все проблемы фреймворка можно сжать в одну: нужно чётко понимать, как его готовить. Если изначально выстроить аккуратный подход, то возможные боли при масштабировании практически нивелируются. Иными словами, у нашей команды есть тактика, и мы должны её придерживаться.
Пройдёмся по каждому из минусов отдельно.
Tailwind — неинформативное решение
Представим, что мне нужно что-то продебажить в UI. Например, проблема в карточке ритейлера. Я часто начинаю дебаг с того, что открываю DevTools и ищу нужный мне компонент по названию класса.
Вот пример нехитрой навигации в проекте, стилизованном с SCSS. Всё весьма просто и прозрачно.

Tailwind отберёт у вас понятные, читаемые названия классов. Вместо чего-то семантичного вы получите sticky top-0 z-40 w-full и так далее.
Как с этим справиться? Можно просто добавить дата-атрибуты. Да, вы никуда не денетесь от портянки классов. Как «упаковать» их красиво — так и не придумали. Да, останутся непонятные длинные имена, но вы сможете навигироваться по DOM-дереву, сможете искать. Тестировщики скажут вам спасибо, потому что дата-атрибуты очень полезны для автоматизации тестирования.
Ещё одно простое и очевидное решение — красиво разделить код на компоненты. Если у вас React, используем его DevTools, и вот искать что-то по дереву компонентов снова просто и приятно. Если не React — расстраиваемся и переходим на React. Это, конечно, шутка, все инструменты для своих задач.
В Tailwind слишком много классов, и запоминать их трудно
Иногда я слышу что-то в таком стиле: «Инструмент классно подходит для прототипов. Правда, мы с ним раньше не работали, но хотим что-то накидать на коленке». Это не очень хорошая история, на коленке не получится. При старте с нуля много времени уйдёт на то, чтобы понять, какие вообще есть классы, как правильно готовить фреймворк, чтобы работа выстроилась более-менее системно.
Логика здесь простая: чем больше вы пишете, тем лучше запоминается. Набор классов всё же ограничен. Как всегда, тренировка и потраченные часы рабочего времени сделают своё дело.
Помимо этого, для решения проблемы есть волшебное расширение IntelliSense. Вы ставите его в VS Code или любую популярную IDE и получаете удобный Tailwind-саджестор: расширение подсказывает вам возможные варианты. Поначалу приходится часто смотреть документацию и пользоваться дополнительными средствами, чтобы ориентироваться в коде. Но, когда вы напишете 10-20 компонентов, всё дойдёт до состояния полного автоматизма, и проблема отпадёт.

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

Код становится достаточно читаемым, если использовать библиотеку classNames или что-то подобное.
Мы работаем с ней так: бьём длинный класс на небольшие подклассы, которые семантически объединяем по экранам. Можно дробить классы по другим признакам, например — в зависимости от значений пропсов. Декомпозиция здесь — наше всё. И всегда стоит помнить про компонентный подход: чем аккуратнее и точнее мы дробим, тем меньше громоздких классов у нас будет в будущем.
Однако важно сказать, что по волшебству всё это не происходит. Держите в голове командные договорённости либо ужесточайте правила ESLint или другого линтера. Иначе будет сложно контролировать, чтобы люди писали код правильно. Плагин eslint-plugin-tailwindcss даёт набор правил, который можно использовать для поддержки кода. Он отсортирует и упорядочит классы, запретит использовать неконсистентные значения.
Стилизация в Tailwind непереиспользуемая, плохо масштабируемая и бессистемная
Про переиспользование. В Tailwind есть очень полезная директива @apply, которая добавляет ваши кастомные классы на слой компонентов и позволяет использовать их везде. Это значит, что вы можете написать отдельный класс и использовать в нём набор других классов.
@layer components { .btn-primary { @apply py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75; } }
А теперь вы можете расширить директивой класс любого элемента. Достаточно удобно!
Использование таких apply-классов даёт нам возможность экспортировать целые наборы стилей. Грубо говоря, я могу написать свои компоненты, вынести все стили в общую core-библиотеку и переиспользовать в других своих проектах!
Про масштабируемость. Фреймворк предоставляет пользователю очень гибкий конфиг. Есть tailwind.config.js, который создаётся в корне вашего проекта, когда вы инитите Tailwind. Он даёт возможность настроить всё так, как вам необходимо. С помощью этого конфига вы можете строго ограничить команду разработчиков, дав им доступ лишь к типографике, цветам, отступам, которые предусмотрены именно вашей дизайн-системой. На скрине описан вид поведения boxShadow и цветов.

С трейдоффами выше вполне можно смириться, часть из них разрешается позитивно. Мы либо улучшаем опыт взаимодействия, либо привыкаем.
Однако в Tailwind есть проблемы, с которыми действительно тяжело.
Легко получить неконтролируемую свалку классов
Например, у нас есть такой класс:

Разраб использовал всё, что только можно, скомбинировав:
-
Кривой и несемантичный дата-атрибут.
-
Отступы в пикселях, в отрицательных значениях и в rem.
-
Цвета в текстовых значениях и через hex.
Получилось очень мусорно и не очень читаемо. Вы скажете, что кейс неорганический, а я скажу вам, что в коде стартапов встречается и не такое ? Поэтому важно договариваться либо ужесточать ESLint. Выше я уже писал об этом, но это так важно, что позволю себе повториться.
Другого решения нет, только так.
Большинство кастомных решений в Tailwind неудобные и сложные
Прежде чем считать это проблемой, задайте себе вопрос, часто ли вам нужно изобретать велосипед. Библиотека классов огромная, и найти что-то можно практически под любые нужды.

Но есть ситуации, когда персональный велосипед вам точно нужен. Например, Tailwind не умеет в clip-path. Инструмент развивается, у него выходят новые версии, но да, в данный момент действительно есть ряд юзкейсов, которые остались без имплементации.
Вы всегда можете написать нативный CSS и закрепить его на утилитах через директиву @layer. Вроде ничего сложного, но давайте представим, что вы каждый раз пишете под любое более-менее кастомное решение такой кусочек. Страшно подумать, во сколько раз вырастут затраты времени и сил. Если стилизация проекта слишком кастомная, лучше подумайте десять раз, стоит ли использовать Tailwind.
Из коробки нет RTL
Встроенного RTL в Tailwind не предусмотрено в принципе. В вашем проекте он может быть и не нужен, но кто знает, из какой страны в стартап придут инвесторы.
Отличное комьюнити фреймворка решило эту проблему библиотекой tailwindcss-rtl. Она даёт дополнительный набор классов, с которыми ваш RTL заведётся без какого-либо труда. Недаром говорят: «Добавьте к любому слову .js — и вы получите какую-то существующую NPM-библиотеку». Здесь комьюнити действительно решает!
Аксессибилити хромает
Допустим, у нас есть div, который должен быть прочитан только скринридером и не должен отображаться в UI. Для этого нам дают класс sr-only, который абсолютно позиционирует элемент, скрывает его и применяет ряд дополнительных стилизаций. На этом всё — больше из коробки ничего в Tailwind просто нет.
Вселяет надежду находящийся на этапе тестирования пакет Tailwind CSS Beta 2 с плюшками аксессибилити вроде атрибутов aria-* разных классов. Они позволяют определять совместимость браузера с тем или иным CSS-решением. Есть и много других полезных фич.
Раз уж мы заговорили про NPM-пакеты, мне будет грустно, если я не скажу, что в связке с React вы можете писать кроссплатформенные стили, используя что-то из этой пары классных пакетов: один, два. UI будет переиспользуемым: мы можем собрать React Native под Web, используя что-то вроде react-native-web, и вкупе со стилизацией на Tailwind получить мощнейшее комбо.
Комьюнити Tailwind даёт нам ещё и готовые UI-киты (например, tailwind-kit). Вы берёте готовый код, копипастите его в свой проект, стилизованный с Tailwind, и всё. Всё работает, никаких дополнительных библиотек не нужно.

Как любой инструмент, Tailwind имеет свои трейдоффы, но он быстрый и кроссплатформенный. Когда вы выйдете на пик кривой обучения, потратив N часов и написав M компонентов, всё станет интуитивно понятно, работа по стилизации пойдёт в удовольствие.
Масштабируем ли код, написанный с Tailwind? Да, но его нужно уметь готовить. Если вы не будете договариваться либо не будете использовать свои жёсткие правила для ESLint, у команды ничего не получится.

Tailwind даёт классное комьюнити: если использовать его силу, можно реализовать практически любую идею. Для меня это решение оказалось удобным и хорошо масштабируемым в рамках проекта. Остальные выводы каждый волен делать самостоятельно. Использовать или нет — решать вам.
Tech-команда СберМаркета ведет соцсети с новостями и анонсами. Если хочешь узнать, что под капотом высоконагруженного e-commerce, следи за нами в Telegram и на YouTube. А также слушай подкаст «Для tech и этих» от наших it-менеджеров.
ссылка на оригинал статьи https://habr.com/ru/companies/sbermarket/articles/737474/
Добавить комментарий