Tailwind CSS 怎么复用样式?

文章导读
Previous Quiz Next Tailwind CSS 采用 utility-first approach,通过应用小型、专注的单用途 class 来构建设计。这种方法有助于避免代码复杂性并保持一致性。
📋 目录
  1. 多光标编辑
  2. 循环
  3. 提取组件和部分模板
  4. 与 CSS 抽象相比
  5. 使用 Tailwind 的 @apply 指令提取类
  6. 避免过早抽象
A A

Tailwind CSS - 复用样式


Previous
Quiz
Next

Tailwind CSS 采用 utility-first approach,通过应用小型、专注的单用途 class 来构建设计。这种方法有助于避免代码复杂性并保持一致性。

在项目开发中,你可能会发现自己在多个地方使用相同的 utility class 集合。与其为重复样式编写 custom CSS,不如使用 Tailwind 的 utility classes 来高效处理这些重复。

以下是一个简单的示例,在网页上显示 profile widgets,每个 widget 都应用了相同的 utility class 三次。

示例

 
<!DOCTYPE html>
<html lang="en">
<head> 
    <script src="https://cdn.tailwindcss.com"></script>
</head>

<body class="p-4 bg-gray-100">
    <div class="flex space-x-4 overflow-x-auto p-4 bg-gray-200">
        <!-- Profile Widget 1 -->
        <div class="flex-shrink-0 w-56 p-4 bg-white border border-gray-300
                    rounded-lg shadow-lg flex flex-col items-center space-y-3">
            <div class="mb-3">
                <img class="h-20 w-20 rounded-full border-4 border-cyan-500 
                            shadow-md" src="https://randomuser.me/api/portraits/men/1.jpg" 
                            alt="Profile Picture"/>
            </div>
            <div class="text-center">
                <h3 class="text-lg font-semibold text-gray-800 mb-1">John Doe</h3>
                <p class="text-gray-600 text-sm mb-2">Tech Enthusiast</p>
                <p class="text-gray-500 text-xs">John has over 5 years of 
                    experience in the tech industry, focusing on software 
                    development and innovation.
                </p>
            </div>
        </div>

        <!-- Profile Widget 2 -->
        <div class="flex-shrink-0 w-56 p-4 bg-white border border-gray-300 
                    rounded-lg shadow-lg flex flex-col items-center space-y-3">
            <div class="mb-3">
                <img class="h-20 w-20 rounded-full border-4 border-rose-500 
                            shadow-md" src="https://randomuser.me/api/portraits/women/2.jpg" 
                            alt="Profile Picture"/>
            </div>
            <div class="text-center">
                <h3 class="text-lg font-semibold text-gray-800 mb-1">
                  Jane Smith
                </h3>
                <p class="text-gray-600 text-sm mb-2">UI/UX Designer</p>
                <p class="text-gray-500 text-xs">Jane is a skilled UI/UX 
                    designer with 3 years of experience in creating intuitive user
                    interfaces and enhancing user experiences.
                </p>
            </div>
        </div>

        <!-- Profile Widget 3 -->
        <div class="flex-shrink-0 w-56 p-4 bg-white border border-gray-300 
                    rounded-lg shadow-lg flex flex-col items-center space-y-3">
            <div class="mb-3">
                <img class="h-20 w-20 rounded-full border-4 border-violet-500 
                            shadow-md" src="https://randomuser.me/api/portraits/men/3.jpg" 
                            alt="Profile Picture"/
                >
            </div>
            <div class="text-center">
                <h3 class="text-lg font-semibold text-gray-800 mb-1">
                    Alice Johnson</h3>
                <p class="text-gray-600 text-sm mb-2">Data Scientist</p>
                <p class="text-gray-500 text-xs">Alice has 7 years 
                    of experience as a data scientist, specializing in data 
                    analysis and machine learning.
                </p>
            </div>
        </div>
    </div>
</body>

</html>

别担心!我们将帮助你理解如何在项目中 复用样式,以及何时有效使用每种方法。

使用编辑器和语言特性

通常,重复样式不是问题,因为它们集中在一处或通过循环生成,因此你只需编写一次代码。

如果在单个文件中工作,可以使用多光标编辑同时更改多行。对于重复元素,使用循环从单段代码生成它们。这能保持工作高效且有条理。

多光标编辑

多光标编辑 是许多文本编辑器中的一项功能,它允许你在文档的不同位置放置多个光标。这让你可以同时在多个位置进行相同的更改,非常适合快速更新重复内容。

当单个文件中存在重复的样式或元素时,多光标编辑可以帮助你一次性修改它们。让我们看一个例子来了解它是如何工作的。

假设你有一个项目列表,你想将每个项目的 class bg-red-100 更新为 bg-teal-100

示例

<!DOCTYPE html>
<html lang="en">
<head> 
    <script src="https://cdn.tailwindcss.com"></script>
</head>

<body class="p-4">
    <h3 class="font-bold underline mb-4">
        List of Item in Shopping cart:
    </h3>
    <ul class="shopping-cart">
        <li class="bg-red-100 p-2">Apples</li>
        <li class="bg-red-100 p-2">Bananas</li>
        <li class="bg-red-100 p-2">Oranges</li>
        <li class="bg-red-100 p-2">Grapes</li>
    </ul>
</body>

</html>

添加光标

按住 Alt 键,然后在代码中每个 bg-red-100 旁边点击。这会在你点击的每个位置放置一个光标,所有光标就位后,输入 bg-teal-100。所有 bg-red-100 实例将同时更新为 bg-teal-100。

更新后的代码:

<ul class="shopping-cart">
    <li class="bg-teal-100 p-2">Apples</li>
    <li class="bg-teal-100 p-2">Bananas</li>
    <li class="bg-teal-100 p-2">Oranges</li>
    <li class="bg-teal-100 p-2">Grapes</li>
</ul> 

你可能会发现,使用多光标编辑 通常是处理重复样式的最简单方法。它能让你一次性更新所有实例,无需额外的工具或方法。

循环

循环 在编程中让处理重复元素变得更容易。无需反复编写相同的代码,你可以使用循环自动创建相同的 HTML 结构。因此,在 web 项目中使用重复的设计元素时,有效使用循环非常重要。

在为每个重复的设计元素创建单独的组件或自定义类之前,先检查该元素是否被使用多次。

例如,本指南开头展示的 profile widgets 使用相同设计重复了三次。我们可以使用循环从单个模板生成多个元素,而不是单独编写每个 widget。下面来看看这个示例是如何实现的。

示例

<!DOCTYPE html>
<html lang="en">
<head> 
    <script src="https://cdn.tailwindcss.com"></script>
</head>

<body class="p-4">
    <div id="profile-container" class="flex space-x-4 overflow-x-auto 
        p-4 bg-gray-200">
    <!-- 个人资料小部件将动态插入此处 -->
    </div>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
          const profiles = [
            { name: "John Doe", role: 
                "Tech Enthusiast", 
                imgSrc: "https://randomuser.me/api/portraits/men/1.jpg", 
                    
                        borderColor: "border-cyan-500" },
            { name: "Jane Smith", role: "UI/UX Designer", 
                imgSrc: "https://randomuser.me/api/portraits/women/2.jpg", 
                    borderColor: "border-rose-500" },
            { name: "Alice Johnson", role: "Data Scientist", 
                imgSrc: "https://randomuser.me/api/portraits/men/3.jpg", 
                    borderColor: "border-violet-500" }
          ];
    
          const container = document.getElementById('profile-container');
          profiles.forEach(profile => {
            container.innerHTML += `
              <div class="flex-shrink-0 w-56 p-4 bg-white border 
                border-gray-300 rounded-lg shadow-lg flex flex-col items-center space-y-3">
                <div class="mb-3">
                  <img class="h-20 w-20 rounded-full border-4 ${profile.borderColor} shadow-md" 
                    src="${profile.imgSrc}" alt="Profile Picture"/>
                </div>
                <div class="text-center">
                  <h3 class="text-lg font-semibold text-gray-800 mb-1">
                    ${profile.name}</h3>
                  <p class="text-gray-600 text-sm mb-2">
                    ${profile.role}</p>
                  <p class="text-gray-500 text-xs">Profile description here.</p>
                </div>
              </div>
            `;
          });
        });
    </script> 
</body>

</html>

使用循环意味着你只需编写一次标记,避免重复并使更新变得更容易。它高效管理动态数据,并确保更改只需在一个地方应用。

提取组件和部分模板

如果您想在不同文件中重用样式,如果您使用像 ReactSvelteVue 这样的前端框架,那么创建一个 component 是个好主意。如果您使用像 BladeERBTwigNunjucks 这样的模板语言,您应该创建一个 template partial。这种方法有助于保持代码的组织性,并使维护变得更容易。

示例

<!DOCTYPE html>
<html lang="en">
<head> 
  <script src="https://cdn.tailwindcss.com"></script>
</head>

<body class="p-4">
  <div class="testimonial-sectio">
        <div class="testimonial-card p-4 bg-white border border-gray-300 
                    rounded-lg shadow-lg">
            <img class="w-16 h-16 rounded-full border-2 border-gray-300" 
              src="https://randomuser.me/api/portraits/men/1.jpg" 
                  alt="Alice Johnson's photo" />
            <h3 class="mt-2 text-lg font-semibold text-gray-800">
                Alice Johnson
            </h3>
            <p class="mt-1 text-gray-600">
                This service is fantastic! It exceeded all my expectations.
            </p>
        </div>
        
        <div class="testimonial-card p-4 bg-white border border-gray-300 
                    rounded-lg shadow-lg mt-4">
            <img class="w-16 h-16 rounded-full border-2 border-gray-300" 
              src="https://randomuser.me/api/portraits/women/2.jpg" 
                  alt="Bob Smith's photo" />
            <h3 class="mt-2 text-lg font-semibold text-gray-800">
                Bob Smith
            </h3>
            <p class="mt-1 text-gray-600">
                An excellent experience from start to finish.
            </p>
        </div>
    </div>
</body>

</html>

对于上面的示例,在 React 中使用 Tailwind CSS 创建一个 TestimonialCard component,并根据项目需要使用它任意多次。下面是一个您可以用来显示 testimonials 的 functional component

示例

// TestimonialCard.jsx
import React from 'react';

const TestimonialCard = ({ name, photo, testimonial }) => (
    <div className="p-4 bg-white border border-gray-300 rounded-lg shadow-lg">
        <img 
            className="w-16 h-16 rounded-full border-2 border-gray-300" 
            src={photo} 
            alt={`${name}'s photo`} 
        />
        <h3 className="mt-2 text-lg font-semibold text-gray-800">{name}</h3>
        <p className="mt-1 text-gray-600">{testimonial}</p>
    </div>
);

export default TestimonialCard;

要在您的应用或设计中使用 TestimonialCard component,只需导入它并提供必要的 props。

示例

// App.jsx
import React from 'react';
import TestimonialCard from './TestimonialCard';

const App = () => (
    <div className="p-4 bg-gray-100">
        <div className="flex space-x-4">
            <TestimonialCard
                name="John Doe"
                photo="https://randomuser.me/api/portraits/men/1.jpg"
                  testimonial="John's experience was wonderful. 
                  The service was top-notch and exceeded expectations."
            />
            <TestimonialCard
                name="Jane Smith"
                photo="https://randomuser.me/api/portraits/women/2.jpg"
                  testimonial="Jane had a fantastic experience! 
                  Highly recommended for anyone looking for quality service."
            />
        </div>
    </div>
);

export default App;

在任何地方使用这个 component,并从一个地方轻松更新样式。

与 CSS 抽象相比

在设计 web 界面时,CSS 单独使用不足以处理复杂组件。您需要同时使用 HTML 和 CSS 来有效处理详细的 UI 元素。

以“进度跟踪器”为例。与其使用 CSS 为每个步骤单独设置样式,不如使用组件将每个步骤的 HTML 和 CSS 结合在一起。

示例

<!DOCTYPE html>
<html lang="en">
<head> 
  <script src="https://cdn.tailwindcss.com"></script>
</head>

<body class="flex justify-center items-center h-screen bg-gray-100">
    <div class="w-full max-w-3xl px-4 py-6 bg-white rounded-lg shadow-md">
        <div class="text-center mb-8 text-gray-800">
            <p class="text mb-4 ml-4">
                This tracker shows your progress through different stages:
            </p>
            <ul class="list-disc list-inside text-left text-gray-600">
                <li><strong class="text-green-500">Completed:</strong> 
                    Finished steps
                </li>
                <li><strong class="text-yellow-500">Current:</strong>
                    The active step
                </li>
                <li><strong class="text-gray-300">Upcoming:</strong>
                    Future steps
                </li>
            </ul>
        </div>
        <div class="relative flex items-center">
            <div class="absolute inset-0 flex items-center pointer-events-none">
                <div class="flex-1 h-1 bg-green-500"></div>
                <div class="flex-1 h-1 bg-yellow-400"></div>
                <div class="flex-1 h-1 bg-gray-300"></div>
                <div class="flex-1 h-1 bg-gray-300"></div>
            </div>
            <!-- Steps -->
            <div class="flex-1 text-center relative z-10">
                <div class="w-12 h-12 rounded-full bg-green-500 text-white 
                    flex items-center justify-center mx-auto mb-2 text-2xl"></div>
                <div class="text-sm">Step 1</div>
            </div>
            <div class="flex-1 text-center relative z-10">
                <div class="w-12 h-12 rounded-full bg-yellow-500 text-white 
                    flex items-center justify-center mx-auto mb-2 text-2xl"></div>
                <div class="text-sm">Step 2</div>
            </div>
            <div class="flex-1 text-center relative z-10">
                <div class="w-12 h-12 rounded-full bg-gray-200 text-white 
                    flex items-center justify-center mx-auto mb-2 text-2xl"></div>
                <div class="text-sm">Step 3</div>
            </div>
            <div class="flex-1 text-center relative z-10">
                <div class="w-12 h-12 rounded-full bg-gray-200 text-white
                    flex items-center justify-center mx-auto mb-3 text-2xl"></div>
                <div class="text-sm">Step 4</div>
            </div>
            <div class="absolute right-0 top-1/2 w-1/4 h-px bg-gray-300"></div>
        </div>
    </div>
</body>

</html>
 

即使您使用 class 进行样式设置,每次使用组件时仍需重复编写 HTML。虽然更新字体大小很简单,但仅用 CSS 进行更复杂的更改(如将标题转换为链接)则很困难。

组件template 部分模板更好,因为它们将 HTMLstyles 结合在一起。这样,您只需在一个地方更新字体大小或将所有标题更改为链接。

考虑使用 template partialJavaScript component 来获得更简单的解决方案。

示例

import React from 'react';

function Step({ status, number }) {
    const statusClasses = {
        completed: 'bg-green-500',
        current: 'bg-yellow-500',
        upcoming: 'bg-gray-200'
    };

    return (
        <div className="flex-1 text-center relative z-10">
            <div className={`w-12 h-12 rounded-full ${statusClasses[status]} 
                text-white flex items-center justify-center mx-auto mb-2 text-2xl`}>
                {status === 'completed' ? '' : status === 'current' ? '' : ''}
            </div>
            <div className="text-sm">Step {number}</div>
        </div>
    );
}

function ProgressTracker() {
    return (
        <div className="relative flex items-center">
            <div className="absolute inset-0 flex items-center pointer-events-none">
                <div className="flex-1 h-1 bg-green-500"></div>
                <div className="flex-1 h-1 bg-yellow-400"></div>
                <div className="flex-1 h-1 bg-gray-300"></div>
                <div className="flex-1 h-1 bg-gray-300"></div>
            </div>
            <Step status="completed" number={1} />
            <Step status="current" number={2} />
            <Step status="upcoming" number={3} />
            <Step status="upcoming" number={4} />
            <div className="absolute right-0 top-1/2 w-1/4 h-px bg-gray-300"></div>
        </div>
    );
}

export default ProgressTracker;

使用 componentstemplate 部分模板时,您只需使用 utility classes,因为样式在一个地方处理。

使用 Tailwind 的 @apply 指令提取类

在设计网页时,反复使用相同的 utility classes 会让你的 HTML 变得杂乱且难以管理。Tailwind CSS 通过 @apply 指令 来帮助解决这个问题。

@apply 是什么以及何时使用它?

@apply 指令允许你通过应用一组 Tailwind utility classes 来创建自定义 CSS 类。这可以将重复的样式移到你的 CSS 文件中,使 HTML 更简洁。

虽然 template partials 适用于复杂组件,但 @apply 非常适合频繁使用的样式。它能保持你的 HTML 简洁,并确保样式一致性。

在使用 @apply 之前,你可能会在 HTML 中直接添加多个 utility classes 来样式化一张卡片。

示例

<!DOCTYPE html>
<html lang="en">
<head> 
    <script src="https://cdn.tailwindcss.com"></script>
</head>

<body class="p-4 bg-gray-200">
    <div class="p-6 max-w-sm mx-auto bg-white rounded-lg shadow-md">
        <h2 class="text-xl font-bold mb-2">Card Title</h2>
        <p class="text-gray-700 ">
            This is a card component styled with Tailwind utilities.
        </p>
    </div>
</body>

</html>

使用 @apply 之后:在 CSS 中为卡片定义一个自定义类,然后在 HTML 中使用它:

<div class="card">
    <h2 class="card-title">Card Title</h2>
    <p class="card-content">
        This is a card component 
        styled with Tailwind utilities.
    </p>
</div>

使用 @apply 的 CSS

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

@layer components {
  .card {
    @apply p-6 max-w-sm mx-auto bg-white rounded-lg shadow-md;
  }
  .card-title {
    @apply text-xl font-bold mb-2;
  }
  .card-content {
    @apply text-gray-700;
  }
}

使用 @apply 指令可以帮助你组织样式并使代码更简洁。

避免过早抽象

不要仅仅为了清理 HTML 就使用 @apply。这看似是个好主意,但可能会带来更多问题:

  • 命名问题: 想出类名可能会很累人。
  • 多次编辑: 过度使用 @apply 意味着需要在 CSS 和 HTML 之间不断切换。
  • 样式变更: 对一个类的更改可能会无意中影响网站的其他部分。
  • 更大的 CSS 文件: 许多自定义类会增加 CSS 文件大小并影响性能。

@apply 用于小型、可重用项如按钮,或者在像 React 这样的框架中使用组件来更好地管理。