Главная » Статьи » Прощайте CSS-модули, привет TailwindCSS

Прощайте CSS-модули, привет TailwindCSS

Прощайте CSS-модули, привет TailwindCSS

От автора: редизайн приложения никогда не бывает рутинным и простым. Через две недели после того, как меня приняли на работу в Polytomic, я начал реализовывать первый редизайн приложения с момента основания компании. Выбор технологии и способы ее реализации оставались за мной.

Кодовая база нашего фронтенда — это одностраничное приложение на базе Create React App (CRA), написанное на TypeScript и использующее GraphQL для API. Существующий подход к стилизации использовал модули CSS без системы дизайна.

Модули CSS — это файлы CSS, в которых по умолчанию все имена классов и анимаций имеют локальную область видимости. Они компилируются как часть этапа сборки — с помощью технологии создания пакетов, такой как Webpack, — и изначально поддерживаются CRA.

Пример использования обыкновенного CSS в React:

/* Button.css */
.Button { padding: 20px;
}

// Button.tsx
import * as React 'react'
// Tell webpack that Button.tsx uses these styles
import './Button.css' export function Button () { // You can use them as regular CSS styles return <div className='Button'>Button</div>
}

<!-- Corresponding HTML -->
<div class='Button'>Button</div>

Пример использования CSS-модулей в React:

/* Button.module.css */
.error { background-color: red;
} /* another-stylesheet.css */
.error { color: red;
}

// Button.tsx
import * as React from 'react'
// Import css modules stylesheet as styles
import styles from './Button.module.css' // Import regular stylesheet
import './another-stylesheet.css' export function Button() { // reference as a js object return <button className={styles.error}>Error Button</button>
}

<!-- Corresponding HTML -->
<!-- This button has a red background but not red text. No clashes from other .error class names.
-->
<button class='Button_error_ax7yz'>Error Button</button>

Преимущества модулей CSS заключаются в устранении конфликтов CSS между файлами в локальной области видимости, явных зависимостей и предотвращении глобального CSS. Но предотвращение глобального CSS удаляет выразительную силу «каскадной» части Каскадных Таблиц Стилей (CSS). Кроме того, локальная область видимости имен и идентификаторов классов CSS не предотвращает дублирование CSS в других файлах. Определение margin-top:0; несколько раз в разных файлах CSS не будут устранены модулями CSS.

Самый большой недостаток CSS-модулей — отсутствие утилит системы проектирования. Для фронтенд-команды, состоящей из одного человека, это было препятствием. Мне нужен был мощный и выразительный подход к стилизации с утилитами для создания и поддержки дизайн-системы.

Что такое дизайн-система?

Дизайн-система — это набор повторно используемых компонентов и стилей для создания связного пользовательского интерфейса. Он абстрагирует определенные значения в пользу общих токенов или переменных.

Например, цветовая палитра будет использовать имена, передающие результат, такие как color-success или color-warning, вместо буквальных значений или названий цветов, таких как зеленый или # FFA500. Обновление значения color-success превращается в однострочное изменение, которое распространяется на все экземпляры этого токена.

Дизайн-системы определяют результат во всех аспектах пользовательского интерфейса, от простых цветов до сложных компонентов. Ограничения на выбор стиля гарантируют, что доступные варианты гармонично сочетаются друг с другом. Создание визуально несбалансированного макета или компонента становится сложнее, чем с модулями CSS и отсутствием системы дизайна.

Twitter Bootstrap стал пионером концепции CSS-фреймворка и библиотеки компонентов. Это отличный выбор для готовых компонентов. Однако самая большая особенность Bootstrap — готовые компоненты — может быть его самым большим недостатком.

Bootstrap — это закрытая система. В прошлых проектах я переписывал и переопределял большие части библиотеки Bootstrap, чтобы настроить переменные стиля и компоненты, которые конфигурация не позволяла настраивать. Но если настройка является требованием по умолчанию, эффективность Bootstrap теряется. Использование модулей CSS привело бы к тому же объему работы с тем же результатом, что и пользовательский Bootstrap.

Помня о системах дизайна и настройке, я сузил список вариантов до Tailwind и Theme UI. Обе библиотеки предлагают мощную конфигурацию системы проектирования, но, что особенно важно, не ограничивают меня конкретными компонентными архитектурами. Я хотел избежать утомительного процесса переопределения, присутствующего в готовых библиотеках компонентов, таких как Bootstrap.

Сравнивая Tailwind с Bootstrap, Tailwind представляет собой набор примитивов стиля, основанных на конфигурации. Это аспект конфигурации Bootstrap без заранее подготовленных компонентов или привязки к компонентам и архитектуре конфигурации.

У Tailwind есть собственная платная библиотека компонентов под названием Tailwind UI, которая является современным эквивалентом Bootstrap. Она использует гибкость конфигурации Tailwind, обеспечивая при этом высококачественные рецепты компонентов, которые легко изменить и настроить. Я использовал Tailwind UI в качестве отправной точки и вдохновения для собственных компонентов.

Что такое Tailwind?

Tailwind — это утилитарный CSS-фреймворк, представляющий этап сборки, наполненный такими классами, как flex, pt-4, text-center и rotate-90, которые можно скомпоновать для создания любого дизайна непосредственно в разметке.

Утилитарный класс CSS — это подход к написанию CSS, который изменяет определение правил стиля. Исторически сложилось так, что CSS написан с несколькими правилами стиля, привязанными к одному классу, идентификатору или элементу HTML.

Пример с обыкновенным CSS:

/* button.css */
.button { background-color: rgb(243, 244, 246); border-radius: .5rem; color: rgb(0, 0, 0); cursor: pointer; font-family: 'Inter var', 'Helvetica Neue', Arial, sans-serif; font-size: 1rem; font-weight: 500; line-height: 1.5rem; padding-top: .75rem; padding-bottom: .75rem; text-align: center;
}

<!-- Corresponding HTML -->
<div class='button'>Button</div>

Служебные классы определяют каждое правило стиля как отдельный класс для индивидуальной компоновки в разметке вместо определения необходимых правил стиля в рамках одного класса. Например, в stylesheet.css:

/* stylesheet.css */
.font-sans { font-family: 'Inter var', 'Helvetica Neue', Arial, sans-serif;
}
.text-base { font-size: 1rem; line-height: 1.5rem;
}
.font-medium { font-weight: 500;
}
.rounded-lg { border-radius: .5rem;
}
.bg-gray-100 { background-color: rgb(243, 244, 246);
}
.text-black { color: rgb(0, 0, 0);
}
.py-3 { padding-top: .75rem; padding-bottom: .75rem;
}
.text-center { text-align: center;
}
.cursor-pointer { cursor: pointer;
}

<!-- Corresponding HTML -->
<div class='text-base font-sans font-medium rounded-lg bg-gray-100 text-black py-3 text-center cursor-pointer'>Button</div>

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

Оставаясь в рамках ограничений системы проектирования и API Tailwind, использовать новое значение для заполнения так же просто, как вставить py-2 в разметку. Tailwind заранее сгенерировал этот класс из значений по умолчанию и конфигурации. Он также сгенерировал py-1 и py-4, но удалит их из таблицы стилей, если они не добавлены в разметку.

Что такое CSS-in-JS?

CSS-in-JS — это общая философия написания CSS внутри файлов JavaScript. Написание всех стилей происходит в файлах JavaScript и способом, присущим JavaScript, а не CSS. Это позволяет стилю CSS-in-JS использовать всю выразительную мощь JavaScript.

Theme UI — это библиотека CSS-in-JS для создания тематических пользовательских интерфейсов на основе принципов проектирования основаных на ограничениях. Это разновидность CSS-in-JS для простого CSS-подхода Tailwind. Оба выполняют одну и ту же задачу — системы проектирования, но различаются опытом разработки.

Пример файла конфигурации Tailwind для переопределения или расширения конфигурации по умолчанию:

// tailwind.config.js
module.exports = { theme: { fontFamily: { heading: ['Inter', 'system-ui', 'sans-serif'], body: ['Inter', 'system-ui', 'sans-serif'], }, colors: { primary: { 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc', 400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca', 800: '#3730a3', 900: '#312e81', }, gray: { 50: '#fafafa', 100: '#f4f4f5', 200: '#e4e4e7', 300: '#d4d4d8', 400: '#a1a1aa', 500: '#71717a', 600: '#52525b', 700: '#3f3f46', 800: '#27272a', 900: '#18181b', }, }, },
}

// app.tsx
export const App = () => ( <div> <h1 className='font-heading text-primary-500'> Hello </h1> </div>
)

Пример объекта конфигурации Theme UI:

// theme.ts
import type { Theme } from 'theme-ui' export const theme: Theme = { fonts: { body: 'system-ui, sans-serif', heading: '"Avenir Next", sans-serif', monospace: 'Menlo, monospace', }, colors: { text: '#000', background: '#fff', primary: '#33e', },
}

// app.tsx
import { ThemeProvider } from 'theme-ui';
import { theme } from './theme' export const App = () => ( <ThemeProvider theme={theme}> <h1 sx={{ color: 'primary', fontFamily: 'heading', }} > Hello </h1> </ThemeProvider>
)

Поскольку и Tailwind и Theme UI помогают реализовать системы дизайна, я выбрал Tailwind, потому что CSS не заблокирован внутри среды выполнения JavaScript. Он компилируется в обычные классы CSS. Размер пакета JavaScript меньше, потому что определения стилей не связаны с кодом React. Поскольку Tailwind использует глобальные классы CSS с низкой специфичностью, переопределение правил таблиц стилей устраняется, а размер файла не увеличивается.

Стратегия реализации

Я начал свое путешествие по внедрению редизайна с небольшой простой страницы в приложении, чтобы убедить себя, что использование Tailwind было жизнеспособной стратегией. Убедившись, что Tailwind будет работать, я занялся оставшимися страницами в порядке убывания сложности.

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

Каждый раз, когда я внедрял функцию на master в старом дизайне, мне нужно было делать rebase моей ветки редизайна и заново реализовывать работу, что могло быть простым рестайлингом или серьезным рефакторингом. Проблема синхронизации новых функций усугублялась тем, что другие инженеры выполняли свою работу. Если бы я подождал пару дней, чтобы перенастроить свою ветку редизайна на master — как я наивно поступил вначале — я бы потратил до часа на разрешение конфликтов. Оглядываясь назад, можно сказать, что последовательное изменение настроек на раннем этапе было правильной стратегией.

Заключение

Редизайн был завершен несколько месяцев назад, что дало мне достаточно времени, чтобы оценить мое решение использовать Tailwind. Мой вывод: выбор однозначно удачный. Основные причины:

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

Общий язык: команда разработчиков Polytomic использует дизайн-систему Tailwind. При реализации функции я могу рассчитывать на макеты дизайна, придерживающиеся значений и масштабов Tailwind.

Выразительность: я смог воплотить в жизнь все, что мне давали. Tailwind меня не ограничил. Когда я использовал CSS, отличный от Tailwind, это было только для определенных браузеров, в основном – для Safari.

Контекстные настройки: многие компоненты нуждаются в настройках CSS в зависимости от их контекста. Для меня изменение строки className, а не переопределение CSS через каскад, менее подвержено ошибкам. Устранена проблема коллизий специфичности.

Оглядываясь назад, я бы сделал выбор в пользу Tailwind снова.

Автор: Brett Flora

Источник: www.polytomic.com

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен