Skip to content

Tailwind CSS - 重用样式

Tailwind 的“工具优先”(utility-first)方法在快速构建定制设计方面非常强大。然而,随着项目的增长,你不可避免地会遇到重复的工具类模式。有效管理这种重复是维护整洁和可扩展代码库的关键。

本指南涵盖了现代样式复用策略,从简单的编辑器技巧到强大的基于组件的架构,帮助你决定哪种方法最适合你的情况。

通常,你最终 HTML 中看起来像是重复的代码,实际上是由模板中的循环或数据列表生成的。这并非真正的重复,因为你只需一次性编写模板标记。

这是处理类似项目列表(例如博客文章、产品卡片或用户资料)最常用且首选的方法。样式在循环模板中定义一次,数据提供独特的内容。

示例:从数组生成个人资料卡片

Section titled “示例:从数组生成个人资料卡片”

在这里,我们定义一个 JavaScript 用户数据数组,并使用 forEach 动态创建每个个人资料卡片的 HTML。如果我们需要更改卡片的样式,只需在一个地方进行编辑。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Profile Cards</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 p-8">
<div id="profile-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<!-- 个人资料卡片将在此处动态插入 -->
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const profiles = [
{
name: 'Alex Johnson',
role: 'Lead Developer',
imgSrc: 'https://randomuser.me/api/portraits/men/1.jpg',
borderColor: 'border-blue-500',
bio: 'Alex is a full-stack expert with a passion for clean code and modern frameworks.'
},
{
name: 'Maria Garcia',
role: 'UX/UI Designer',
imgSrc: 'https://randomuser.me/api/portraits/women/2.jpg',
borderColor: 'border-pink-500',
bio: 'Maria crafts beautiful, intuitive, and accessible user experiences.'
},
{
name: 'Kenichi Tanaka',
role: 'DevOps Engineer',
imgSrc: 'https://randomuser.me/api/portraits/men/3.jpg',
borderColor: 'border-teal-500',
bio: 'Kenichi ensures our infrastructure is scalable, reliable, and secure.'
}
];
const container = document.getElementById('profile-container');
if (container) {
profiles.forEach(profile => {
const profileCardHTML = `
<div class="flex flex-col items-center p-6 bg-white rounded-xl shadow-lg transform hover:scale-105 transition-transform">
<img class="h-24 w-24 rounded-full border-4 ${profile.borderColor} object-cover" src="${profile.imgSrc}" alt="${profile.name}'s profile picture" />
<h3 class="text-xl font-semibold text-gray-900 mt-4">${profile.name}</h3>
<p class="text-gray-600">${profile.role}</p>
<p class="text-gray-500 text-sm text-center mt-2">${profile.bio}</p>
</div>
`;
container.innerHTML += profileCardHTML;
});
}
});
</script>
</body>
</html>

当你需要在不同页面或上下文中重用一个 UI 片段时,将其提取为一个可重用组件是最佳实践。这是 React、Vue 和 Svelte 等现代框架中的标准方法,也可以通过 Blade (Laravel) 或 Twig (Symfony) 等服务器端模板语言实现。

组件封装了HTML 结构和 Tailwind 类,提供了一个单一的真理来源。然后,你可以通过 props 将数据传递给组件以自定义其内容。

示例:React 中的可复用 TestimonialCard 组件

Section titled “示例:React 中的可复用 TestimonialCard 组件”

首先,我们定义 TestimonialCard 组件。它接受 name、photo 和 testimonial 作为 props。

components/TestimonialCard.jsx
import React from 'react';
// 这是一个函数式 React 组件。
// 它接收 props(数据)并返回 JSX(类似 HTML 的语法)。
const TestimonialCard = ({ name, photo, testimonial, company }) => {
return (
<figure className="flex flex-col items-center p-6 bg-white rounded-xl shadow-lg">
<img
className="w-20 h-20 rounded-full object-cover"
src={photo}
alt={`Photo of ${name}`}
/>
<blockquote className="mt-4 text-center text-gray-700 italic">
<p>"{testimonial}"</p>
</blockquote>
<figcaption className="mt-4 font-semibold text-gray-900">
{name}
<div className="text-sm text-gray-500 font-normal">{company}</div>
</figcaption>
</figure>
);
};
export default TestimonialCard;

然后,我们可以在应用程序的任何地方导入和使用此组件,保持代码整洁和 DRY(Don’t Repeat Yourself,不要重复自己)。

pages/HomePage.jsx
import React from 'react';
import TestimonialCard from './components/TestimonialCard';
const App = () => {
const testimonialsData = [
{ name: 'John Doe', company: 'TechCorp', photo: '...', testimonial: 'This service is fantastic!' },
{ name: 'Jane Smith', company: 'Innovate LLC', photo: '...', testimonial: 'An excellent experience from start to finish.' },
];
return (
<div className="bg-gray-100 p-8">
<h2 class="text-3xl font-bold text-center mb-8">What Our Clients Say</h2>
<div className="grid md:grid-cols-2 gap-8 max-w-4xl mx-auto">
{testimonialsData.map((data, index) => (
<TestimonialCard key={index} {...data} />
))}
</div>
</div>
);
};
export default App;

Tailwind 的 @apply 指令允许你将一系列工具类提取到一个新的自定义 CSS 类中。这对于非常小、通用且广泛重复的 UI 元素很有用,在这些情况下创建一个完整的组件可能感觉过于繁琐。

何时使用 @apply(以及何时不使用)

Section titled “何时使用 @apply(以及何时不使用)”

好的使用场景:

  • 按钮:btn-primary、btn-secondary。
  • 表单输入:.form-input、.form-label。
  • 样式化来自 CMS 的内容:在无法直接添加类的原始 HTML 上应用样式(例如 Markdown 输出)。

警告:避免过早抽象! 过度使用 @apply 是一种常见的反模式。它可能会让你回到编写 CSS 的老路上,你必须为所有东西发明类名,并不断在 HTML 和 CSS 文件之间切换。始终优先选择组件提取或循环。

/* 在你的主 CSS 文件中,例如 src/input.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn-primary {
@apply py-2 px-4 bg-blue-600 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;
}
.btn-secondary {
@apply py-2 px-4 bg-gray-600 text-white font-semibold rounded-lg shadow-md hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-opacity-75;
}
}

现在你可以在 HTML 中直接使用这些类:

<button class="btn-primary">Submit</button>
<button class="btn-secondary">Cancel</button>