Как стать автором
Обновить
СберМаркет
Кодим будущее доставки товаров

Чем хорош и чем плох Tailwind CSS, или «Допустим, у вас стартап!»

Время на прочтение7 мин
Количество просмотров19K

Привет, Хабр! Меня зовут Александр Водолазских. Я живу в Новосибирске и я работаю 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-решением. Есть и много других полезных фич.

https://github.com/tailwindlabs/tailwindcss/discussions/9574

Раз уж мы заговорили про 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-менеджеров.

Теги:
Хабы:
Всего голосов 17: ↑15 и ↓2+13
Комментарии15

Публикации

Информация

Сайт
sbermarket.ru
Дата регистрации
Дата основания
Численность
1 001–5 000 человек
Местоположение
Россия
Представитель
SberMarket Tech