Just-in-Time: Следующее поколение Tailwind CSS
Tailwind CSS на GitHubTailwind CSS в Telegram

Извлечение компонентов

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

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

Человек смотрит на товар в магазине
Пример использования
Поиск клиентов для вашего нового бизнеса

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

<div class="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">
  <div class="md:flex">
    <div class="md:flex-shrink-0">
      <img class="h-48 w-full object-cover md:w-48" src="/img/store.jpg" alt="Человек смотрит на товар в магазине">
    </div>
    <div class="p-8">
      <div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">Пример использования</div>
      <a href="#" class="block mt-1 text-lg leading-tight font-medium text-black hover:underline">Поиск клиентов для вашего нового бизнеса</a>
      <p class="mt-2 text-gray-500">Начало нового бизнеса - это тяжелая работа. Вот пять идей, которые вы можете использовать, чтобы найти своих первых клиентов.</p>
    </div>
  </div>
</div>

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

<!-- Повторение этих классов для каждой кнопки может быть болезненным -->
<button class="py-2 px-4 bg-green-500 text-white font-semibold rounded-lg shadow-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-opacity-75">
  Нажмите на меня
</button>

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


Извлечение компонентов шаблона

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

Не полагайтесь на классы CSS для извлечения сложных компонентов

<style>
  .vacation-card { /* ... */ }
  .vacation-card-info { /* ... */ }
  .vacation-card-eyebrow { /* ... */ }
  .vacation-card-title { /* ... */ }
  .vacation-card-price { /* ... */ }
</style>

<!-- Даже с настраиваемым CSS вам все равно нужно дублировать эту HTML-структуру -->
<div class="vacation-card">
  <img class="vacation-card-image" src="..." alt="Beach in Cancun">
  <div class="vacation-card-info">
    <div>
      <div class="vacation-card-eyebrow">Частная вилла</div>
      <div class="vacation-card-title">
        <a href="/vacations/cancun">Расслабляющий курорт "все включено" в Канкуне</a>
      </div>
      <div class="vacation-card-price">$299 за ночь</div>
    </div>
  </div>
</div>

По этой причине часто лучше извлекать повторно используемые части Вашего пользовательского интерфейса в части шаблона или компонентах JavaScript вместо написания пользовательских классов CSS.

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

Создайте частичный шаблон или компонент JavaScript

<!-- In use -->
<VacationCard
  img="/img/cancun.jpg"
  imgAlt="Пляж в Канкуне"
  eyebrow="Частная вилла"
  title="Расслабляющий курорт "все включено" в Канкуне"
  pricing="$299 за ночь"
  url="/vacations/cancun"
/>

<!-- ./components/VacationCard.vue -->
<template>
  <div>
    <img class="rounded" :src="img" :alt="imgAlt">
    <div class="mt-2">
      <div>
        <div class="text-xs text-gray-600 uppercase font-bold">{{ eyebrow }}</div>
        <div class="font-bold text-gray-700 leading-snug">
          <a :href="url" class="hover:underline">{{ title }}</a>
        </div>
        <div class="mt-2 text-sm text-gray-600">{{ pricing }}</div>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    props: ['img', 'imgAlt', 'eyebrow', 'title', 'pricing', 'url']
  }
</script>

В приведенном выше примере используется Vue, но тот же подход можно использовать с компонентами React, ERB partials, компонентами Blade, Twig includes и т. д.


Извлечение классов компонентов с помощью @apply

Для небольших компонентов, таких как кнопки и элементы формы, создание части шаблона или компонента JavaScript часто может показаться слишком тяжелым по сравнению с простым классом CSS.

В таких ситуациях вы можете использовать директиву Tailwind @apply, чтобы легко извлекать общие служебные шаблоны в классы компонентов CSS.

Вот как может выглядеть класс btn-indigo при использовании @apply для его составления из существующих утилит:

<button class="btn-indigo">
  Нажмите на меня
</button>

<style>
  .btn-indigo {
    @apply py-2 px-4 bg-indigo-500 text-white font-semibold rounded-lg shadow-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-400 focus:ring-opacity-75;
  }
</style>

Чтобы избежать непреднамеренных проблем со специфичностью, мы рекомендуем обернуть ваши стили пользовательских компонентов директивой @layer components { ... }, чтобы сообщить Tailwind, к какому слою принадлежат эти стили:

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

@layer components {
  .btn-blue {
    @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;
  }
}

Tailwind автоматически переместит эти стили в то же место, что и @tailwind components, так что вам не нужно беспокоиться о правильном порядке в Ваших исходных файлах.

Использование директивы @layer также проинструктирует Tailwind учитывать эти стили для очистки при очистке слоя components. Прочтите нашу документацию по оптимизации для продакшена для получения более подробной информации.

Как и в случае с пользовательскими утилитами, вы можете генерировать responsive, hover, focus, active и другие варианты своих собственных компонентов, используя директиву @variants:

/* ... */

@layer components {
  @variants responsive, hover {
    .btn-blue {
      @apply py-2 px-4 bg-blue-500 ...;
    }
  }
}

Подробнее читайте в документации директивы @variants.

Написание плагина компонента

Помимо написания классов компонентов непосредственно в Ваших файлах CSS, вы также можете добавить классы компонентов в Tailwind, написав свой собственный плагин:

// tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  plugins: [
    plugin(function({ addComponents, theme }) {
      const buttons = {
        '.btn': {
          padding: `${theme('spacing.2')} ${theme('spacing.4')}`,
          borderRadius: theme('borderRadius.md'),
          fontWeight: theme('fontWeight.600'),
        },
        '.btn-indigo': {
          backgroundColor: theme('colors.indigo.500'),
          color: theme('colors.white'),
          '&:hover': {
            backgroundColor: theme('colors.indigo.600')
          },
        },
      }

      addComponents(buttons)
    })
  ]
}

Это может быть хорошим выбором, если вы хотите опубликовать компоненты Tailwind в виде библиотеки или упростить совместное использование компонентов в нескольких проектах.

Подробнее читайте в документации подключаемого модуля к компоненту.