Сайт вебмастера

Краткий обзор Tailwind CSS

10-07-2020Время чтения ~ 7 мин.CSS, HTML, LESS, SASS 10539

Расскажу немного о Tailwind CSS, поскольку этот фреймворк позиционируется как утилитарный и мне интересен в сравнении и моими UniCSS и Berry CSS.

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

Важный момент в том, что Tailwind написан на JS, то есть там нет css-кода как такового. Его идея в том, чтобы подключать нужные компоненты как js-модули, которые в свою очередь генерируют нужный css-код. Наверное именно поэтому его используют в js-фреймворках на node.js - сборка получается скопом, как там и принято.

Если абстрагироваться от самого сборщика, то идея генерировать css-классы ровно такая же, как и в моём UniCSS (и Berry). Я это реализован в конце 2014 года на Less (потом перешел на Sass), а Tailwind появился на 3 года позже со сборщиком на JS. В нём используется тот же самый подход, когда верстальщик сам указывает какие именно классы ему нужны.

Если взять готовый tailwind.min.css, то он, конечно очень большой — 1,3Мб. Из-за того, что в нём не используется Sass, то невозможно собрать свой css-файл из того, что требуется. Это очень сильно ограничивает возможности вёрстки.

Поэтому оценивать Tailwind CSS можно по его семантике и примерам. Поскольку это utility-first CSS framework, то на нём можно делать практически всё. В нём много css-классов под самые разные задачи.

Вы можете посмотреть небольшой сайт с готовыми примерами, чтобы оценить возможности фреймворка.

Документация Tailwind CSS тоже очень хорошо сделана: — это то, чего у меня никак не получается сделать для Berry CSS... Уже есть.

Сбросы

Структурно Tailwind похож на Berry CSS. Он включает сбросы normalize и border-box, но при этом зачем-то обнуляет стили для многих тэгов как это раньше использовалось в reset.css. Эта особенность может негативно сказаться на верстке - не зря мы перешли от сбросов к «нормализации» стилей браузера.

Лично меня всегда «убивал» сброс списков:

ol, ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

Ну вот в Tailwind CSS это до сих пор используется.

Сброс border-box тоже сделан «забавно»:

*,::after,::before {
  box-sizing: border-box;
  border-width: 0;
  border-style: solid;
  border-color: #e2e8f0;
}

Зачем для всех after и before стили для border для меня загадка.

Сбросы очень важны при вёрстке, поскольку определяют начальное отображение всех элементов во всех браузерах. Сейчас стандарт — это normalize + сброс border-box и ничего более. Поэтому, когда фреймворк добавляет что-то ещё, то это гарантированно сбивает вёрстку.

Например в Bootstrap'е вместо полноценного normalize добавляется ещё куча своих стилей, вроде margin, color для заголовков и это невозможно отключить — приходится либо править исходный scss-файл, либо переопределять css-стили дальше по коду.

Поскольку Tailwind — не предлагает типографику как таковую, то также остаётся загадкой для чего вообще были добавлены эти сбросы. Специфика утилитарных фреймворков именно в том, что они создают только css-классы, но не меняют «голые» html-тэги.

Качество CSS-кода

В Tailwind активно используется var(). Во многих случаях такой css-код вызывает вопросы:

.bg-black {
  --bg-opacity: 1;
  background-color: #000;
  background-color: rgba(0,0,0,var(--bg-opacity));
}

Это как бы ради поддержки IE8? Хотя официально заявлено о IE10/11, а значит такой код избыточен.

Да и само использование css-переменных немного странное, можно сократить так:

.bg-black {
  background-color: rgba(0,0,0,var(--bg-opacity, 1));
}

Что уменьшило бы размер css-кода. Но, есть одна тонкость. Часть классов используют css-переменные для перепределения своего поведения.

.lg\:transform {
  --transform-translate-x: 0;
  transform: translateX(var(--transform-translate-x)) ... ;
}
 
.translate-x-3 {
  --transform-translate-x: 0.75rem;
}

То есть идея в том, чтобы использовать css-переменные для своих «внутренних» задач. Если для transform это ещё может быть хоть как-то оправдано, перенос этой схемы на другие классы уже не имеет смысла. Например для цвета:

.sm\:text-black {
  --text-opacity: 1;
  color: #000;
  color: rgba(0,0,0,var(--text-opacity));
}
 
.focus\:text-opacity-25:focus {
  --text-opacity: 0.25;
}

То есть все эти css-переменные используются ради десятка focus/hover-классов. Если посчитать объём «--text-opacity: 1;», то он значительно превысит размер обычных стилей. Также не стоит забывать, что для браузера var() — это всё-таки динамический контент, а значит их большое количество может приводить к увеличению потребления CPU.

Вот такой код:

.space-y-0>:not(template)~:not(template) {
  --space-y-reverse: 0;
  margin-top: calc(0px * calc(1 - var(--space-y-reverse)));
  margin-bottom: calc(0px * var(--space-y-reverse));
}

Помимо переменных содержит ещё и calc(). Перенос расчётов в CSS достаточно сложная тема, но я на этот пример указываю для того, чтобы показать ради чего он используется — задание отступов между колонками:

<div class="flex space-x-4">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>

Я, когда столкнулся с подобной задачей, остановился на обычных padding и margin ячеек. При адаптивности, если нужно, эти отступы обнуляются (это отдельные классы). Либо просто добавляется пустая ячейка вместо отступов. В других фреймворках часто используются какие-то предопределённые классы ячеек, чтобы управлять их поведением.

В Tailwind же, в данном случае стреляет из пушки по воробьям, слишком усложняя css-код, вместо того, чтобы просто добавить классы для ячеек.

Семантика css-классов

Ну да, тут я могу сколько угодно изголяться, :-) поскольку Tailwind CSS изобилует такими классами:

.w-16, .w-32, .w-2/4, .max-w-xl, .m-5, .-m-40, .my-1, .-mt-px, .mr-56, .p-px, .px-10, .px-px, .pt-56, .pl-1, .max-w-6xl, .text-3xl, .leading-5, .tracking-wider, .align-top, .inset-x-0

Вот .w-16 — это width: 4rem; — понять это невозможно. Чтобы задать width: 50% нужно использовать классы: .w-1/2, .w-2/4 и т.д. При этом получить ширину 23%, 31% или 48% (частая задача) уже нельзя.

С другими примерами похожая ситуация. Попробуйте сами понять смысл этих классов, потом удивитесь их реальному назначению. :-)

Семантика таких классов определилась историческим путём и сохраняется ради совместимости. Я и сам несколько раз менял классы, когда разрабатывал UniCSS. Например для width я использую префикс «w», поскольку это уже была устоявшаяся практика. А вот margin и padding я менял несколько раз, поскольку слишком длинный префикс влияет на размеры css-кода, а короткий, вроде «m» и «p» несемантичны. Поэтому я вышел на компромис mar и pad. Автор Tailwind видимо, не рискнул совместимостью, поэтому такие классы сохранились.

Но, если смотреть на другие, то в целом используется достаточно понятная семантика основанная на css-свойствах, вроде .font-bold. Хотя .font-black уже сбивает с толку — это не черный цвет, а font-weight: 900;. Логичней было бы тогда использовать .font-bold-900.

То есть с одной стороны семантика хромает, но если держать под рукой документацию, можно к ней привыкнуть.

Цвета

Цвета задаются произвольно через отдельную конфигурацию. Можно сформировать свою палитру и произвольные имена классов, так же как и в Berry CSS.

Дефолтная палитра состоит из 9 цветов + серый. Всё строится на гугуловском дизайне с градациями от 100 до 900 (9 градаций). Сейчас это фактически стандарт.

На практике такого количества цветов мало, поэтому она годится только для «общей» верстки. Когда будет стоять задача сверстать макет более точно, придётся добавлять свои цвета. Я в Berry использую 15 цветов + серый, причем каждый в 19 градациях (от 50 до 950). То есть палитра такая, что ей может пользоваться дизайнер при выборе цвета. Это влияет на размер кода, но поскольку можно отключить неиспользуемые оттенки, то css-файл можно сократить в несколько раз.

В Tailwind CSS автоматически генерируются классы для текста, фона и бордюра. На самом деле бордюры обычно имеют очень немного цветов, поэтому делать для них массу классов не имеет смысла. Поэтому в Berry — это отдельная настройка (а также для классов .links-XXX).

Но в целом в Tailwind CSS уже общепринятый подход к цветам, который прост и понятен:

.text-purple-200
.bg-orange-700
.border-gray-200

Сравните с Berry CSS:

.t-purple200
.bg-orange700
.bor-gray200

То есть принципиальной разницы нет.

Особенности семантики

Отдельно вынес этот пункт, чтобы обратить на него внимание. В Tailwind часть классов использует символ «:», например:

sm:border-green-500 
md:border-indigo-500 
lg:border-red-500
focus:placeholder-indigo-800

В данном случае этот символ указывает на некий «модификатор»: адаптивность или состояние focus и т.п. В других фреймворках часто используют символ «@», например в UiKit:

uk-width-1-2@m
uk-visible@l
uk-text-center@l

Такие классы выглядят достаточно красиво, но непривычно и сбивают с толку. Обычно в качестве разделителя в классах используется только символ «-», а все другие нужно запоминать, поскольку они а) разные и б) указываются в разных частях класса.

То есть сейчас такой подход только формируется. Тем более, что символ «:» хорош именно для псеводоэлементов в CSS, как-то так:

hover:t-red
focus:bor-gray600

И использование его для модификатора адаптивности несколько сбивает с толку. Возможно со временем сформируется какой-то единый подход.

Выводы

Чем мне нравится Tailwind CSS, так это его поддержка и популярность. Значит многие верстальщики уже перешли на современную вёрстку utility-first. Вопросы семантики — это такое — одному нравится одно, другому другое, да и привыкнуть можно к любому варианту. Если отбросить теже margin/padding, то в принципе особых сложностей не возникает. Чем собственно и хороши утилитарные библиотеки, что они очень легко расширяются: нет вообще никаких проблем сформировать свой css-класс с любым именем.

Но я вижу две проблемы. Первая — это качество (и размер) css-кода. Если его нормально «причесать», то размер значительно уменьшится и можно будет пользоваться даже готовым дистрибутивом.

И вторая проблема — работа через JS. Обычно вёрстка делается через Sass, поэтому на текущий момент Tailwind CSS расcчитан только на js-программистов и js-фреймворки, поскольку позволяет выполнять выборочную сборку и настройку. В других вариантах, к сожалению, это не работает.

А вы уже пробовали верстать с помощью утилитарных классов?

Похожие записи
Комментарии (3) RSS
1 Виктор 2020-07-10 17:46:46

А Вы не думали писать английскую версию статьи?

И поискать англоязычную площадку для публикации, раз уж коснулись концептуальных вещей?


2 RAD 2020-07-10 18:10:59

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


3 Admin 2020-07-10 20:10:27 admin
И поискать англоязычную площадку для публикации, раз уж коснулись концептуальных вещей?

Мне это не особо интересно. :-) Да и за Tailwind особо не переживаю — у них своя большая команда, которая решила что им это так нужно. Я скорее это тему затронул, поскольку считаю, что утилитарные фреймворки у нас почему-то не популярны, хотя на западе они активно используются. Тут ещё и то, что они реально смогли поднять такой проект. Там как-то команды создаются и поддерживают тех, кто может «архитектурно» мыслить. Нам до этого 200 лет ещё развиваться...

Ребята действительно хорошо вложились в раскрутку я смотрю, вот даже публикации некоторым блогерам проплатили.

Они не просто вложились, но ещё и сами выступают спонсорами других известных проектов. Юмор, что мне они заплатили, оценил. :-)

заново родить Atomic CSS

Это не Atomic CSS. Есть принципиальная разница в том, что «чистый» Atomic CSS собирается из исходного html-кода. А здесь именно utility-first, то есть набор заранее подготовленных css-классов. Таких фреймворков уже достаточно, но именно Tailwind достиг такой популярности.