Интеграция с Tailwind и class-variance-authority

SvelteKit предоставляет мощный каркас для создания современных веб-приложений на основе Svelte. Одним из ключевых аспектов разработки интерфейсов является эффективная стилизация компонентов. Комбинация Tailwind CSS и class-variance-authority (CVA) обеспечивает гибкий, декларативный подход к управлению классами и состояниями компонентов.


Настройка Tailwind CSS в проекте SvelteKit

Для начала необходимо установить Tailwind CSS и его зависимости:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init tailwind.config.cjs -p

Конфигурационный файл tailwind.config.cjs позволяет указать пути к файлам, где Tailwind должен искать классы:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './src/**/*.{html,js,svelte,ts}'
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Включение Tailwind в SvelteKit осуществляется через src/app.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

Импорт этого файла в src/routes/+layout.svelte обеспечивает глобальную доступность классов:

<script lang="ts">
  import "../app.css";
</script>

<slot />

Использование class-variance-authority (CVA)

class-variance-authority (CVA) — это библиотека для декларативного управления комбинациями CSS-классов на основе состояний компонента. Она особенно полезна в сочетании с Tailwind, где часто возникают длинные цепочки утилитарных классов.

Установка CVA:

npm install class-variance-authority

Основная идея CVA — создание функции cva, которая возвращает строку классов на основе переданных опций. Пример для кнопки:

import { cva } from 'class-variance-authority';

const button = cva(
  'px-4 py-2 font-semibold rounded-md transition-colors',
  {
    variants: {
      color: {
        primary: 'bg-blue-600 text-white hover:bg-blue-700',
        secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
      },
      size: {
        small: 'text-sm',
        medium: 'text-base',
        large: 'text-lg',
      },
      disabled: {
        true: 'opacity-50 cursor-not-allowed',
      }
    },
    defaultVariants: {
      color: 'primary',
      size: 'medium',
      disabled: false,
    },
  }
);

Использование в SvelteKit компоненте:

<script lang="ts">
  import { button } from './buttonStyles';
  export let color: 'primary' | 'secondary' = 'primary';
  export let size: 'small' | 'medium' | 'large' = 'medium';
  export let disabled: boolean = false;
</script>

<button class={button({ color, size, disabled })} disabled={disabled}>
  <slot />
</button>

Такой подход минимизирует повторение классов и упрощает поддержку сложных UI.


Динамические классы и состояния

CVA позволяет управлять динамическими состояниями без использования условных операторов в шаблоне Svelte. Например, для кнопки с состоянием загрузки:

const loadingButton = cva(
  'px-4 py-2 font-semibold rounded-md flex items-center justify-center gap-2',
  {
    variants: {
      loading: {
        true: 'cursor-wait opacity-70',
        false: '',
      },
      color: {
        primary: 'bg-blue-600 text-white hover:bg-blue-700',
        secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
      },
    },
    defaultVariants: {
      loading: false,
      color: 'primary',
    },
  }
);

Использование:

<script lang="ts">
  import { loadingButton } from './buttonStyles';
  export let loading: boolean = false;
</script>

<button class={loadingButton({ loading })} disabled={loading}>
  {#if loading}
    Загрузка...
  {:else}
    Отправить
  {/if}
</button>

Такой подход позволяет легко расширять компонент новыми вариантами без дублирования классов.


Комбинация Tailwind и CVA для сложных компонентов

CVA особенно полезна для сложных компонентов, таких как карточки, модальные окна, табы, формы. Пример карточки с несколькими вариантами состояния:

import { cva } from 'class-variance-authority';

export const card = cva(
  'rounded-lg shadow-md p-4 transition-all',
  {
    variants: {
      variant: {
        elevated: 'shadow-lg',
        flat: 'shadow-none border border-gray-200',
      },
      highlight: {
        true: 'ring-2 ring-blue-500',
        false: '',
      },
    },
    defaultVariants: {
      variant: 'flat',
      highlight: false,
    },
  }
);

Использование в SvelteKit:

<script lang="ts">
  import { card } from './cardStyles';
  export let variant: 'elevated' | 'flat' = 'flat';
  export let highlight: boolean = false;
</script>

<div class={card({ variant, highlight })}>
  <slot />
</div>

Такой подход обеспечивает чистую и поддерживаемую архитектуру UI, где стили полностью управляются декларативно через Tailwind и CVA.


Советы по организации стилей

  1. Выделение вариаций — хранить CVA-функции отдельно в src/lib/styles для повторного использования.
  2. Согласованность классов — использовать CVA для всех интерактивных компонентов (кнопки, поля ввода, чекбоксы).
  3. Минимизация инлайн-классов — комбинируя Tailwind и CVA, почти все стили компонента могут быть централизованы.
  4. Расширяемость — новые состояния добавляются через variants без изменения шаблона Svelte.

Tailwind CSS и class-variance-authority создают мощный дуэт для построения масштабируемых интерфейсов в SvelteKit, позволяя управлять сложными комбинациями классов декларативно и поддерживать единый стиль компонентов по всему проекту.