Skip to content

重用样式

管理重复和创建可重用的抽象。

Tailwind 鼓励使用实用程序优先工作流程,其中设计仅使用低级实用程序类实现。这是一种强大的方式,可以避免过早的抽象化和由此带来的痛点。

但当然,随着项目的发展,你将不可避免地发现自己在许多不同的地方重复使用常见的实用工具组合来重新创建相同的设计。

例如,在下面的模板中,您可以看到每个头像图像的实用类被重复五次:

Contributors

204
html
<div>
  <div class="flex items-center space-x-2 text-base">
    <h4 class="font-semibold text-slate-900">Contributors</h4>
    <span class="rounded-full bg-slate-100 px-2 py-1 text-xs font-semibold text-slate-700">204</span>
  </div>
  <div class="mt-3 flex -space-x-2 overflow-hidden">
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="/images/tailwindcss/photo-1491528323818.jpg" alt="">
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="/images/tailwindcss/photo-1550525811033.jpg" alt="">
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="/images/tailwindcss/photo-1500648767791.jpg" alt="">
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="/images/tailwindcss/photo-1472099645785.jpg" alt="">
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="/images/tailwindcss/photo-1517365830460.jpg" alt="">
  </div>
  <div class="mt-3 text-sm font-medium">
    <a href="#" class="text-blue-500">+ 198 others</a>
  </div>
</div>

不要惊慌!在本指南中,您将了解有关在项目中重复使用样式的不同策略,以及何时使用每种策略的最佳实践。

使用编辑器和语言特性

很多时候,这样的重复甚至不是一个真正的问题,因为它们都在同一个地方,或者根本不存在,因为你正在遍历一个项目数组,只写一次标记。

如果您需要重复使用的样式只需要在单个文件内重复使用,多光标编辑和循环是管理任何重复的最简单方法。

多光标编辑

当重复出现在单个文件中的一组元素中时,处理它的最简单方法是使用多光标编辑,一次快速选择和编辑每个元素的类列表。

html
<nav class="flex justify-center space-x-4">
  <a href="/dashboard" class="font-bold px-3 py-2 text-slate-700 rounded-lg hover:bg-slate-100 hover:text-slate-900">Home</a>
  <a href="/team" class="font-bold px-3 py-2 text-slate-700 rounded-lg hover:bg-slate-100 hover:text-slate-900">Team</a>
  <a href="/projects" class="font-bold px-3 py-2 text-slate-700 rounded-lg hover:bg-slate-100 hover:text-slate-900">Projects</a>
  <a href="/reports" class="font-bold px-3 py-2 text-slate-700 rounded-lg hover:bg-slate-100 hover:text-slate-900">Reports</a>
</nav>

你会惊讶地发现,这往往是最佳解决方案。如果你能同时快速编辑所有重复的班级名单,那么引入任何额外的抽象都没有好处。

循环

在你假设需要提取一个组件或创建一个自定义类之前,请确保你在模板中实际上使用了它超过一次。

在渲染的页面中,很多时候,出现多次的设计元素实际上只被编写了一次,因为实际的标记是在循环中渲染的。

例如,本指南开头的重复头像几乎肯定会在实际项目中被渲染成一个循环:

Contributors

204
html
<div>
  <div class="flex items-center space-x-2 text-base">
    <h4 class="font-semibold text-slate-900">Contributors</h4>
    <span class="rounded-full bg-slate-100 px-2 py-1 text-xs font-semibold text-slate-700">204</span>
  </div>
  <div class="mt-3 flex -space-x-2 overflow-hidden">
    {#each contributors as user}
      <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="{user.avatarUrl}" alt="{user.handle}"/>
    {/each}
  </div>
  <div class="mt-3 text-sm font-medium">
    <a href="#" class="text-blue-500">+ 198 others</a>
  </div>
</div>

你甚至可以使用循环或 map 来重写导航示例,如果你愿意的话。

html
<nav className="flex sm:justify-center space-x-4">
  {[
    ['Home', '/dashboard'],
    ['Team', '/team'],
    ['Projects', '/projects'],
    ['Reports', '/reports'],
  ].map(([title, url]) => (
    <a href={url} className="rounded-lg px-3 py-2 text-slate-700 font-medium hover:bg-slate-100 hover:text-slate-900">{title}</a>
  ))}
</nav>

当元素像这样在循环中渲染时,实际的类列表只会被写入一次,因此没有实际的重复问题需要解决。

提取组件和部分

如果您需要在多个文件中重复使用一些样式,最佳策略是在使用前端框架(如 React、Svelte 或 Vue)时创建一个组件,或者在使用模板语言(如 Blade、ERB、Twig 或 Nunjucks)时创建一个模板部分。

Beach
Private Villa
$299 USD per night
vue
<template>
  <div>
    <img class="rounded" :src="img" :alt="imgAlt">
    <div class="mt-2">
      <div>
        <div class="text-xs text-slate-600 uppercase font-bold tracking-wider">{{ eyebrow }}</div>
        <div class="font-bold text-slate-700 leading-snug">
          <a :href="url" class="hover:underline">{{ title }}</a>
        </div>
        <div class="mt-2 text-sm text-slate-600">{{ pricing }}</div>
      </div>
    </div>
  </div>
</template>

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

现在您可以在任意地方使用此组件,同时仍然拥有样式的单一真相来源,这样它们可以在一个地方轻松地一起更新。

与CSS抽象相比

除非一个组件是一个单一的HTML元素,否则仅通过CSS无法捕捉定义它所需的信息。对于任何稍微复杂的东西,HTML结构和CSS一样重要。

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

ChitChat Logo
ChitChat

You have a new message!

html
<!-- 即使使用自定义 CSS,您仍然需要复制以下 HTML 结构 -->
<div class="chat-notification">
  <div class="chat-notification-logo-wrapper">
    <img class="chat-notification-logo" src="/images/chitchat.svg" alt="ChitChat Logo">
  </div>
  <div class="chat-notification-content">
    <h4 class="chat-notification-title">ChitChat</h4>
    <p class="chat-notification-message">You have a new message!</p>
  </div>
</div>

<style>
  .chat-notification { /* ... */ }
  .chat-notification-logo-wrapper { /* ... */ }
  .chat-notification-logo { /* ... */ }
  .chat-notification-content { /* ... */ }
  .chat-notification-title { /* ... */ }
  .chat-notification-message { /* ... */ }
</style>

即使您为组件中的不同元素创建类,每次想要使用该组件时仍然需要复制 HTML。当然,您可以在一个地方更新每个实例的字体大小,但如果您需要将标题变成链接呢?

组件和模板部分比仅使用 CSS 抽象更好地解决了这个问题,因为组件可以封装 HTML 和样式。更改每个实例的字体大小与 CSS 一样简单,但现在你也可以在一个地方将所有标题变成链接。

✓ 创建一个模板部分或 JavaScript 组件

ChitChat Logo
ChitChat

You have a new message!

jsx
function Notification({ imageUrl, imageAlt, title, message }) {
  return (
    <div className="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4">
      <div className="shrink-0">
        <img className="h-12 w-12" src={imageUrl.src} alt={imageAlt}>
      </div>
      <div>
        <div className="text-xl font-medium text-black">{title}</div>
        <p className="text-slate-500">{message}</p>
      </div>
    </div>
  )
}

当您创建组件和模板部分时,没有理由使用除实用类之外的任何东西,因为您已经拥有样式的唯一真实来源。

使用 @apply 提取类

如果你正在使用像ERB或Twig这样的传统模板语言,为像按钮这样小的东西创建一个模板部分可能会感觉过度,与简单的CSS类相比,如 btn

尽管强烈建议您为更复杂的组件创建适当的模板部分,但当模板部分感觉过于笨重时,您可以使用 Tailwind 的 @apply 指令将重复的实用程序模式提取到自定义 CSS 类中。

这是使用 @apply 来组合现有实用程序的 btn-primary 类的样子:

html
<!-- 在提取自定义类之前 -->
<button class="py-2 px-5 bg-violet-500 text-white font-semibold rounded-full shadow-md hover:bg-violet-700 focus:outline-none focus:ring focus:ring-violet-400 focus:ring-opacity-75">
  Save changes
</button>

<!-- 在提取自定义类之后 -->
<button class="btn-primary">
  Save changes
</button>
css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .btn-primary {
    @apply py-2 px-5 bg-violet-500 text-white font-semibold rounded-full shadow-md hover:bg-violet-700 focus:outline-none focus:ring focus:ring-violet-400 focus:ring-opacity-75;
  }
}

函数和指令文档中了解更多关于 @apply@layer 的信息。

避免过早抽象

无论你做什么,都不要只是为了让代码看起来“更整洁”而使用 @apply。是的,HTML 模板中到处都是 Tailwind 类有点丑陋。在一个有大量自定义 CSS 的项目中进行更改更糟糕。

如果你开始为所有东西使用 @apply ,基本上就是再次编写 CSS,并放弃 Tailwind 给你的所有工作流程和可维护性优势,例如:

  • 你必须一直想出类名称——没有什么会像为某些不值得被命名的东西想出类名称那样拖慢你的速度或消耗你的精力。
  • 你必须在多个文件之间跳转以进行更改——这比你在将所有内容放在一起之前想象的要繁琐得多。
  • 改变样式更可怕——CSS 是全局的,你确定可以在那个类中改变 min-width 的值而不会在网站的其他部分出现问题吗?
  • 您的 CSS 打包文件会更大 — 哎呀。

如果你要使用 @apply ,请将其用于非常小的、高度可重复使用的东西,比如按钮和表单控件,即使这样也只有在你不使用像 React 这样的框架时才是更好的选择。

Released under the MIT License.