Tailwind CSS on GitHub

提取组件

处理复用并且保持功能优先项目的可维护性。

Tailwind 鼓励 功能优先 的工作流程,最初仅使用功能类来实现设计以避免不成熟的抽象。

Man looking at item at a store
Case study
Finding customers for your new business

Getting a new business off the ground is a lot of hard work. Here are five ideas you can use to find your first customers.

<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="Man looking at item at a store">
    </div>
    <div class="p-8">
      <div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">Case study</div>
      <a href="#" class="block mt-1 text-lg leading-tight font-medium text-black hover:underline">Finding customers for your new business</a>
      <p class="mt-2 text-gray-500">Getting a new business off the ground is a lot of hard work. Here are five ideas you can use to find your first customers.</p>
    </div>
  </div>
</div>

但是随着项目的成长,您会不可避免的发现自己重复使用通用的功能类组合在许多不同的地方创建相同的组件。这对于类似按钮、表单元素、徽章这样的小组件最为明显。

<!-- Repeating these classes for every button can be painful -->
<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">
  Click me
</button>

在许多组件实例之间保持一长串功能类的同步很快会成为真正的维护负担,因此,当您开始遇到这种痛苦的复制时,提取组件是个好主意。


提取模板组件

定义一个 UI 组件的所有信息可以完全存在于 CSS 中,这非常罕见。与此同时,您也需要使用一些重要的相对应的 HTML 结构。

不要依赖 CSS 类来提取复杂的组件

Beach
Private Villa
$299 USD per night
<style>
  .vacation-card { /* ... */ }
  .vacation-card-info { /* ... */ }
  .vacation-card-eyebrow { /* ... */ }
  .vacation-card-title { /* ... */ }
  .vacation-card-price { /* ... */ }
</style>

<!-- Even with custom CSS, you still need to duplicate this HTML structure -->
<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">Private Villa</div>
      <div class="vacation-card-title">
        <a href="/vacations/cancun">Relaxing All-Inclusive Resort in Cancun</a>
      </div>
      <div class="vacation-card-price">$299 USD per night</div>
    </div>
  </div>
</div>

因此,通常最好将 UI 的可重用部分提取到模板片断或 JavaScript 组件中,而不是编写自定义 CSS 类。

通过为模板创建一个单一源,您可以继续使用功能类,而不会因为在多个地方复制相同的类而造成任何的维护负担。

创建模板片断或者 JavaScript 组件

<!-- In use -->
<VacationCard
  img="/img/cancun.jpg"
  imgAlt="Beach in Cancun"
  eyebrow="Private Villa"
  title="Relaxing All-Inclusive Resort in Cancun"
  pricing="$299 USD per night"
  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 components, ERB partials, Blade components, Twig includes 等。


使用 @apply 抽取组件类

对于按钮和表单元素之类的小型组件,与简单的 CSS 类相比,创建模板片断或 JavaScript 组件通常会感觉过重。

在这种情况下,您可以使用 Tailwind 的 @apply 指令轻松地将通用功能模块提取到 CSS 组件类中。

Here's what a btn-indigo class might look like using @apply to compose it from existing utilities: 这是一个示例,使用 @apply 从现有功能类中组合成 btn-indigo 类:

<button class="btn-indigo">
  Click me
</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 层时考虑使用哪些样式进行清除。

编写组件插件

除了直接在 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 组件发布为库,或者可以更轻松地在多个项目中共享组件,这是一个不错的选择。

查看 组件插件文档 了解更多。