初探Tailwind CSS

发布于 大漠

写CSS有些年头了,经历了不同的时期用不同的姿势来编写CSS,其目的就是给Web元素添加样式。但编写样式着实令人感到烦恼,甚至是效率低下,成本极高。也正因如此,社区中有很多CSS方法论和框架来帮助开发快速有效编写CSS。虽然这些方法论和框架有助于我们快速编写CSS,构建UI组件,但也有令人感到头痛之处,比如冗余的代码,代码的覆盖等。随着功能第一(Utility-First)CSS的出现,让我看到了编写CSS的另一种有效的方式,该方式也被认为是现代Web中构建Web界面最好的选择。其中Utility-First CSS的典型作品之一就是Tailwind CSS。接下来,我们就来了探讨Tailwind CSS,我们将了解基于组件的样式有哪些问题,以及为什么要基于Utility-First CSS来构建组件。

编写CSS的姿势

时至今日,编写CSS有很多方式,也可以基于一些CSS框架来编写。比如2019年CSS状态报告中也有相关的统计:

或许你在项目中已经用了一些CSS方法论,比如BEM、Atomic CSS、OOCSS、SMACSS和ITCSS等,也体验过了在项目中引用社区中优秀的CSS框架,比如大家熟悉的Bootstrap、Foundation等。

随着一些优秀的JavaScript框架(比如,React和Vue)等出现,我们构建Web的方式也变了,也致使我们编写CSS的方式也不同了,社区中有很多关于CSS-in-JS的讨论,同样也有不同的方式方法:

如果你面对众多的编写CSS的姿势和管理维护方式感到困惑的话,建议你可以按照下图的流程来做选择:

有关于这方面的讨论,这里就不做过多的阐述了,如果你感兴趣的话,可以阅读:

虽然这些CSS方法都在试图着帮助我们解决CSS编写和管理的问题,但是如果我们能够编写实用程序类(Utility Class),然后在我们的代码库中重复使用它们,就会更容易一些。这些实用工具类是详尽的,可以作为paddingmarginfont-size等方面的独立指南。

另外实用程序类(Utility Class)将解决重复样式的问题,因为我们不再需要编写任何自定义样式。此外,如果我们的UI风格遵循特定的标准,我们也可以在开发中遵循相同的标准。其中Tailwind CSS就是社区中目前具备这些特点的CSS框架之一。是不是对Tailwind CSS感到好奇,如果是的话,请继续往下阅读。

什么是Tailwind CSS?

**Tailwind CSS**官网是这么描述的:

一个实用的CSS框架,是一个高度可定制的,底层的CSS框架,它为你提供了所有的构建模块,可以快速构建定制设计,也不会有额外的自定义CSS需要去覆盖

换句话说,Tailwind CSS是一个基于实用程序的底层CSS框架,旨在简化Web应用程序的构建,提高事度,减少编写定制CSS的关注,而不需要离开HTML代码的舒适区,同时实现出色的界面。

比如官网首页提供的示例,只需要使用几个类就可以设计出不同的卡片效果(不需要总是声明一个大的类来独立于你的HTML和写一堆属性来制作一些东西):

<div class="md:flex bg-white rounded-lg p-6">
    <img class="h-16 w-16 md:h-24 md:w-24 rounded-full mx-auto md:mx-0 md:mr-6" src="avatar.jpg">
    <div class="text-center md:text-left">
        <h2 class="text-lg">Erin Lindford</h2>
        <div class="text-purple-500">Customer Support</div>
        <div class="text-gray-600">erinlindford@example.com</div>
        <div class="text-gray-600">(555) 765-4321</div>
    </div>
</div>

而且只需要改变HTML中的类名,就可以达到不同的效果:

其他CSS框架(比如我们熟悉的Bootstrap、Foundation、Bulma等)提供了各种预定义组件(比如ModalButtonAlertCard等)。但是有了Tailwind CSS,可以自己做,或者你被迫根据你的项目模型自己做。换句话说,你实际上拥有了组件,你可以在你选择的任何组件上利用你的定制能力。这意味着不再需要与框架斗争,也不需要试图找出需要覆盖哪些类才能获得最初目标的结果。

Tailwind CSS不像Bootstrap

当你看到CSS框架一词时,我想你马上会想到Twitter的 Bootstrap (或类似于Bootstrap的CSS框架)。但它们之间还是存在很大的差异的,其中最大的差异就是:Bootstrap是一组可设定样式笔主题的组件,Tailwind 是一组可配置的实用CSS类;Bootstrap帮助你预构建组件,Tailwind为你提供了快速构建自己组件

用一个按钮的示例来展示他们之间的区别。

先来看HTML代码:

<!-- Bootstrap -->
<button type="button" class="btn btn-primary">Primary</button>

<!-- Tailwind -->
<button class="bg-blue-500 hover:bg-blue-600 text-white py-2 px-2 rounded">Primary</button>

可以看到,在Bootstrap中,HTML要简洁的多,所以你可能会问,既然Bootstrap更简单,为什么不使用它呢?为了回答这个问题,我们来设想有这么一个场景:“如果你想让按钮在特定的页面(或组件)上稍微小一点”?你是否想要为这种独特的情况创建一个新的类,比如Bootstrap中的.btn-sm。在这种情况下,在Tailwind CSS中只需要使用不同的padding类,比如py-1。相比之下要比Bootstrap容易地多,而且你不需要去修改或增加任何CSS代码,而只需要调整HTML中class的值。

而且在Tailwind CSS中和Bootstrap(或类似于Bootstrap的其他CSS框架)最大的不同,在class中可以设置一些状态的类,比如hover:bg-blue-600。这在Bootstrap中从未有过的特性和功能。

另外,在Tailwind CSS中也提供了创建类的可能性,比如在HTML文件中重复多次使用的组,以为该组件创建一个类,比如.btn-blue。那么在Tailwind CSS中可以像下在这样使用:

<!-- Extracting component classes: -->

<button class="btn btn-blue">Button</button>

<style>

    .btn {
        @apply font-bold py-2 px-4 rounded;
    }

    .btn-blue {
        @apply bg-blue-500 text-white;
    }

    .btn-blue:hover {
        @apply bg-blue-700;
    }

</style>

有关于这方面的具体使用,后续会花更多的时间来和大家一起探讨。

接下来,我们再来看一下Bootstrap和Tailwind CSS两个框架中CSS的差异性。同样拿上面的按钮Demo为例:

我想你在上面的截图中已经看出他们之间的差异了:Bootstrap中类的样式是一个集合(会有一个或多个样式);而Tailwind CSS中的每个类对应的仅是一个样式

Tailwind CSS不像 Atomic Design

Tailwind CSS也不像 Atomic Design。了解Atomic Design的同学都知道,在Atomic Design系统中,可以将元素划分为最小单元体,将其称为元子,这些元子可以组合成最终的页面。

但Tailwind CSS的类特别像Atomic Design中的 Atoms。前面的示例可以获知,在元素上运用很多个不同类就能达到想要的UI,甚至是页面的效果。但在Tailwind CSS中这些类不被称为是Atoms 类,而是被称为实用性类(Utility Class)

Tailwind CSS不像 OOCSS

Tailwind CSS也不像OOCSS(Object Oriented CSS)。如果用实际来说的话,Bootstrap中的很多东西更像OOCSS,它里面的一些设计思路就有OOCSS的身影,而Tailwind CSS不像OOCSS,不过Tailwind CSS有OOCSS最核心的设计思想,那就是:内容和结构的分离

在社区中很还很多优秀的CSS方法论和框架,它们有着类似的设计思路或者管理模式,这里就不一一和Tailwind CSS做对比。事实上也是如此,任何一个CSS框架都有着自己的优势和弊端,既然如此,那么为什么要使用Tailwind CSS框架呢?

为什么要用 Tailwind CSS?

在这里我并不想只为Tailwind CSS做推广。或者说,一听说到CSS框架,你的内心就有一种排斥。比如上面做的对比,你可能发现了Tailwind CSS些许优势,即可以做到开箱即用,但也难免要花费时间去了解框架中的功能性类,而且其应用方式也非常不同,自身也有一定的问题。

除此之外,你可能不想从一种熟悉的环境中跳出来去接受一个新的环境,或者还没有被自己说服自己去接受Tailwind CSS带来的好处。那么接下来,我们先抛开这一切,我们从客端上来看,为什么要去用Tailwind CSS。

没有命名约定

在项目中编写CSS最令人头痛的是命名的约定,比如说类的命名,特别是团队多人协助情景下。在很多时候,都在想着怎么给类命名,才不会产生冲突(或尽可能的避免冲突),在思考哪些类应该是通用的,哪些类是特定的。这些问题是CSS一直存在的问题,虽然说CSS-in-JS或者说CSS Modules方法可以帮助我们解决这方面的冲突。但我们在编写组件的时候,还是没有较好的方法可以让CSS和HTML完全解耦。

Tailwind CSS框架采用基于功能性类的方式完美的解决了这些问题,可以让你做到CSS和HTML的解耦,而且也可以做到样式上的开箱即用。

但Tailwind CSS也无法满足你所有的业务场景,你总是需要去添加一些自定义的样式,如果你有一套体系的或者标准的规范,那么就可以像Tailwind CSS框架一样,根据这些规范定制出更属于自己业务场景的功能性类集合。

或许你和我有同样的想法,在HTML中的同一个标签元素上写那么多个类,令你感到恶心,想要一个更清晰的类。那么在Tailwind CSS中你也可以这么做,而且把这种方式称为提取组件类,意思是,当你需要提取某些组件并在以后的设计中使用。针对这样的情景,可以使用Tailwind CSS的@apply指令快速达成。

缓存的好处

在编写CSS(或使用任何其他传统的CSS框架)时,一旦设计做出调整,就必须对CSS做出相应的调整。但是使用Tailwind CSS时,你不需要为此担心,因为Tailwind CSS框架中内聚了很多功能类名,你只需要根据新的设计需求调整HTML中标签元素的类名。这也意味着你不必每次都要调整CSS,破坏CSS的缓存。

可配置

Tailwind CSS另一个优点是,一旦你习惯了语法,它可以加快开发速度。不需要经常在HTML和CSS文件之间来回切换,而且类编写起来很快很容易。如果你在代码编辑器中使用了相匹配的插件,比如VS Code中的 **Tailwind CSS IntelliSense**插件,在编码的时候就可以自动补全,编写起来会更快。

其缺点是需要在配置中进行一些初始化相关的配置工作。Tailwind CSS附带了一个config.js配置文件,其中定义了所有的变量,比如颜色、排版、大小等等。这里有一个默认的配置,但是你很可能需要对它进行大量的定制,这样做确实是值得的。在编写任何代码之前,你可能会感觉花费了大量的时间来进行配置,但这个时间的花费是值得的,因为配置完成之后,在后面的编码阶段会变得更快,更容易。

config.js具体如何配置,后面我们会介绍。

插件机制

因为Tailwind CSS是用JavaScript配置的,所以可以编写函数并将它们传递到配置中。它的优点是为你提供了所有的JavaScript能力,你还可以根据自己的需要编写自己定义的实用程序作为插件。比如:

const plugin = require('tailwindcss/plugin')

module.exports = {
    plugins: [
        plugin(function({ addBase, config }) {
            addBase({
                'h1': { fontSize: config('theme.fontSize.2xl') },
                'h2': { fontSize: config('theme.fontSize.xl') },
                'h3': { fontSize: config('theme.fontSize.lg') },
            })
        })
    ]
}

一般来说,在CSS中添加基本样式要比编写插件要简单得多。但在CSS中添加基本样式也有一些细节需要注意。比如,在平时编写CSS的时候,你可能会使用像Sass这样的处理器,并且在这方面有一定的积累,可以在需要时将它们应用到整个项目中。如果在项目中希望将这些与Tailwind CSS一起使用,可能会导致一定的混乱,因为你可能希望样式被覆盖,但它们并没有被覆盖(哪些样式能被覆盖,这取决于样式导入的顺序,这主要是样式级联和继承造成的)。了解到了这一点之后,我建议你编写自己自定义实用程序作为Tailwind CSS插件,而不是在直接引入一个Sass(或者你自己用其他处理器写的实用程序类)。你可以从这些输出以及所有Tailwind CSS的常规实用程序中获益。

当然,如果你碰到下面这样的场景,应该编写一个插件更合适:

  • 你希望公开发布基本样式,并使其易于其他用户安装
  • 你希望在公司的多个项目中重用基本样式,并希望共享JavaScript依赖项而不是CSS依赖项

虽然使用插件机制能让我们获益不少,但他也有一定的缺点和成本。那就是对于不太熟悉JavaScript的同学来说,成本更大。而且我还认为了解JavaScript(甚至精通JavaScript)的同学不一定能很好的掌握HTML和CSS。换句话说,不认为了解JavaScript应该是编写好的HTML和CSS的先决条件。

状态机制

前面我们有提到过,Tailwind CSS框架和其他的CSS框架有一个最大不同点,那就是Tailwind CSS提供了状态和断点语法,比如下面这样的示例:

<!-- 其他CSS框架状态的运用,比如Bootstrap -->
.button {
    color: #fff;

    &:hover {
        color: #09f;
    }
}

<!-- Tailwind CSS框架中的状态机制 -->

<div class="text-white hover:text-blue"></div>

性能

从理论上来说,实用程序类被设计成可重用的,因此你最终应该交付一个更小的CSS文件。文件越小,性能越好。然而,如果不加修改,Tailwind CSS框架会和其他的CSS框(比如Bootstrap)类似,会将所有类添加到样式文件中,其中会有大量未使用的CSS,除非通过一定的技术手段进行优化,将未使用到的类对应的CSS样式删除。就这一点而言,像Bootstrap这样的框架是很难做的,因为他的出发点就是预定一些样式和组件,以便更好的提供给开发者使用;但Tailwind CSS不同,可以采用一些方法来删除不必要的CSS,从而减少整个样式文件的大小。

Tailwind CSS官方文档中推荐使用PurgeCSS这样的PostCSS插件,该插件对于Tailwind CSS特别有效,因为Tailwind CSS中有数千个类,而其中大多数都有可能在实际项目中用不到(这也是很多人排斥的原因之一)。

具体如何在项目中配置PurgeCSS,在后面的内容中将会涉及到。

什么时候不使用 Tailwind CSS?

你可能也会问?既然Tailwind CSS是一个实用性为最高宗旨的CSS框架,而且有着其独特的优势:能做到开箱即用,快速构建自己所需要的UI。是不是意味着应该在每个项目中都使用Tailwind CSS框架(或者说其他实用性CSS框架)。这当然不是。试想一下,虽然Bootstrap框架在业内非常的优秀,使用的人数众多,但这也并不意味着所有的项目中都要使用Bootstrap,那么Tailwind CSS也是类似的。在一些用例中(或场景中)是不应该使用Tailwind CSS的。

如果你在做一个小项目

当你正在构建一个小型的Web项目或应用时,它有一个非常短的期限,那么Tailwind CSS是不太适合的。在这些情景下,我更建议你使用类似Bootstrap、Foundation的CSS框架。这是因为它们带有预定义的现成组件或主题。如果使用Tailwind CSS,你必须创造性地创建自己的CSS。

如果你是一位CSS的初学者

CSS虽然简单,但要掌握它并不是件易事。

如果你想在Web项目中更好的使用Tailwind CSS的话,就首先要对CSS有所掌握。因为Tailwind CSS是了底层中提供了很多实用程序类,只有对CSS有所掌握(或具有扎实CSS知识)的人才能轻松地使用好Tailwind CSS框架构建Web项目。

如果你不喜欢在HTML标签元素中添加大量的类

通过前面的学习,我想你已经感受到了,在Web项目中使用Tailwind CSS框架的话,最大的感受就是在HTML中的标签元素中使用框架中预设好的实用程序的类。简单地说,就是要在HTML的元素中编写大量的类名,这使得HTML代码变得臃肿难看,有的时候也很难阅读。如果你讨厌这种方式(说实话,我以前也特讨厌这样的姿势),那么就不应该在开发中使用Tailwind CSS框架。

是不是感受到了Tailwind CSS和CSS禅意花园提到的理念刚好相反。在CSS禅意花园中提倡的是在相同的HTML中编写不同的CSS达到不一样的效果;Tailwind CSS提倡的是在相同的CSS框架上在不同的HTML中使用不同的类达到不一样的效果。

不应该在任何场景中使用

有些人特别喜欢Tailwind CSS这样的框架,因此主张在任何项目中都使用该框架。其实我是不推荐这样的方式。拿个示例来说吧。CSS Grid这样的现代Web布局方法,其实是非常的强大,假设你想在实用程序类中预定所有CSS Grid能实现的布局所需的类,那么这个实用程序类就会非常的大,甚至令你感到疯狂。除此之外,并不一定能能够充分的用好CSS Grid的能力。

正如Tailwind CSS中的Grid方面插件,它就这样描述过:

通过实用程序类来展示CSS Grid的所有功能是不现实的

不过Tailwind CSS的网格插件并不具备所有Grid的能力,它只使用了CSS网格来代替使用浮动或Flexbox制作的网格布局。

这仅仅是其中一个示例,CSS的世界既是一个简单的世界也是一个复杂的世界,如果你说Tailwind CSS能涵盖所有CSS属性功能(即使用实用程序类来实现CSS所有属性功能)是不可能的,也是不实用的。因此在任何一个项目都都缺少不了自己定义的CSS。

开始使用 Tailwind CSS?

如果你坚持阅读到这里,说明你对Tailwind CSS有了一个基本了解。那么接下来要我们一起来看看怎么在项目中使用Tailwind CSS框架。

接下来将结合React的开发环境来向大家阐述,在项目中怎么使用Tailwind CSS。

为了设置我们的项目和节约一些时间,将使用create-react-app来构建一个React应用程序。将基于其环境来配置Tailwind CSS所需的配置项。

安装Tailwind CSS

在命令终端执行下面的命令,构建一个React项目:

▶ npx create-react-app app-tailwind-css

然后进入新创建的项目app-tailwind-css,并安装tailwindcss

▶ cd app-tailwind-css && npm i tailwindcss -D

接下来,使用@tailwind指令将Tailwind CSS的basecomponentsutilities引入到项目的CSS文件中。要做到这一点,需要在/src/styles/vendors.css文件中添加以下代码:

// src/styles/vendors.css

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

接下来在package.json文件的scripts中添加build:style

// package.json
"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "build:style": "tailwind build src/styles/vendors.css -o src/styles/tailwind.css"
},

这个时候,你在命令终端执行下面的命令,就会在/src/styles/目录下生成一个名为tailwind.css样式文件:

▶ npm run build:style

这个时候就可以把新生成的tailwind.css引入到项目中,比如/src/App.js文件中:

// src/App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import './styles/tailwind.css'

这个时候你执行npm run start,在浏览器中访问http://localhost:3001/,看到的效果并没有任何变化:

我们的目的是,要在Create React App创建的项目中使用Tailwind CSS,为了验证前面的步骤是否生效,我们可以在/src/App.js<header>元素上添加tailwind.css(也就是Tailwind CSS)中的一个类,比如bg-blue-900

// src/App.js
<div className="App">
    <header className="App-header bg-blue-900"> 
        <!-- 省略不展示的代码 -->
    </header>
</div>

这个时候,你可以看到<header>元素的background-color#282c34变成#2a4365

#2a4365就是Tailwind CSS中的bg-blue-900对应的backround-color。这也说明tailwind.css已在项目中生效了。

配置Tailwind CSS

默认情况下,Tailwind CSS的大小是78.0kb(gzip),而Bootstrap的大小是22.7kb(gzip)。但是,我们可以通过对Tailwind CSS进行配置,减少文件大小。这里不会对所有策略进行介绍。但是,我们将[使用Tailwind的配置文件进行配置]//tailwindcss.com/docs/configuration/),看看怎么减少文件大小。

首先,在命令终端执行下面的这个命令,将会在项目的根目录下创建一个名为tailwind.config.js的配置文件:

▶ npx tailwind init

打开tailwind.config.js文件,可以看到下面这段代码:

// tailwind.config.js
module.exports = {
    theme: {
        extend: {},
    },
    variants: {},
    plugins: [],
}

接下来,我们一起来看,怎么在这个配置文件中添加相关的配置达到我们自己的诉求。

前面多次提到过Tailwind CSS内置了很多实用程序的类,而其中有很多类我们是不会用到的,为了让自己的CSS文件能更小一些,可以使用PurgeCSS来做优化。我们可以使用PurgeCSS的PostCSS插件版本(它也有Webpack版本)。这里我们以PostCSS插件为例。

在使用PostCSS插件之前,首先需要在项目的根目录下创建一个名为postcss.config.js文件,同时在命令终端执行下面的命令来安装PurgeCSS:

▶ npm i @fullhuman/postcss-purgecss cssnano -D

打开postcss.config.js文件,添加有关于PurgeCSS的相关配置:

// postcss.config.js
const purgecss = require("@fullhuman/postcss-purgecss")({
    // 指定项目中所有模板文件的路径
    content: [
        "./src/**/*.html",
        "./src/**/*.vue", //用于Vue项目
        "./src/**/*.jsx",
        "./src/**/*.js",
        "./src/**/*.tsx",
        "./src/**/*.ts",
        "./public/index.html"
        // etc.
    ],

    // 包括在这个正则表达式中使用的任何特殊字符
    defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
});

module.exports = {
    plugins: [...(process.env.NODE_ENV === "production" ? [purgecss, require('cssnano')] : [])]
};

我们需要做的另一件事是对package.json中的一个脚本进行轻微修改。在我们的prebuild中添加NODE_ENV=production为Webpack设置环境变量,其中create-react-app在底层中使用了该变量,并将触发PostCSS CLI在我们样式构建中使用PurgeCSS。

// package.json
"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "build:style": "tailwind build src/styles/vendors.css -o src/styles/tailwind.css",
    "prebuild": "NODE_ENV=production npm run build:style"
},

在命令终端执行:

▶ npm run build && serve -s build

编译出来的结果:

有关于如何在Tailwind CSS中减少文件大小更详细的介绍,还可以阅读官网的相关介绍

如果你查看代码,你会发现目前项目的样式在编译的时候并没有带上私有前缀:

我们需要在Tailwind CSS中配置Autoprefixer,因为Autoprefixer通常会跟踪caniuse.com的数据,查看哪些CSS属性需要添加私有前缀。只需在postcss.config.jspackage.json配置即可:

// postcss.config.js
const tailwindcss = require('tailwindcss');
module.exports = {
    plugins: [
        tailwindcss('./tailwind.config.js'),
        require('autoprefixer'),
        ...(process.env.NODE_ENV === "production" ? [purgecss] : [])
    ]
};

// package.json
"browserslist": [
    ">1%",
    "iOS >= 4",
    "Firefox >= 20",
    "Android > 4.0"
],

这个时候,你可以看到需要前缀的属性就会自动添加私有前缀了:

除了配置PostCSS相关的事项之外,还可以通过tailwind.config.js配置文件覆盖Tailwind的默认调色板或者对调色板进行扩展,还可以禁用某些颜色

在平时的开发中,你或者你的团队已经有一套适合自己团队的样式库,甚至是适合自己的实用程序类库。和Tailwind CSS框架可能会出现问题,Tailwind CSS框架中的实用程序类可能会干扰自己现有的类(特别是类名相同的时候,造成冲突)。对于这样的现象,我们可以在tailwind.config.js配置文件中添加相应的配置,比如给Tailwind CSS框架中的类添加一个前缀来解决。

// tailwind.config.js
module.exports = {
    prefix: 'u-',
    theme: {
        extend: {},
    },
    variants: {},
    plugins: [],
}

保存上面的配置,重新执行npm run build:style命令生成新的tailwind.css文件。那么原有的类前面就会添加前缀u-

这个时候在引用Tailwind CSS的时候,就需要使用带有u-前缀的类名了,比如前面示例中的bg-blue-900,换成u-bg-blue-900

// /src/App.js
<div className="App">
    <header className="App-header u-bg-blue-900">
        <!-- 省略示例代码 -->
    </header>
</div>

这个时候访问页面,看到的效果和前面展示的效果是一样的。

我们在编写CSS的时候,总是难免碰到选择器权重的问题,在使用Tailwind CSS的时候难免也会碰到这样的问题,如果希望让Tailwind CSS框中的类名权重更高,可以在配置文件中给tailwind.css中的类名添加!important来加重选择器权重:

// tailwind.config.js
module.exports = {
    prefix: 'u-',
    important: true,
    theme: {
        extend: {},
    },
    variants: {},
    plugins: [],
}

然后执行npm run build:style,编译之后tailwind.css中的样式会像下面这样:

// src/styles/tailwind.css
.u-bg-black {
    background-color: #000 !important;
}

但不建议通过给样式添加!important来解决选择器权重的问题。这也不是最好的解决方案

扩展Tailwind CSS

前面提到过,我们可能有自己的类库。在Tailwind CSS框架中,除了配置前缀来做区别之外,还可以扩展TTailwind CSS的实用性程序类。在扩展Tailwind CSS时,有一个小细节需要注意,新的实用程序类要放置在@tailwind指令之后。在我们的示例中,就是在/src/styles/vendors.css文件的@tailwind指令后,比如像下面这样:

// /src/styles/vendors.css
@tailwind base;
@tailwind components;
@tailwind utilities;

.rotate-0 {
    transform: rotate(0deg);
}
.rotate-90 {
    transform: rotate(90deg);
}
.rotate-180 {
    transform: rotate(180deg);
}
.rotate-270 {
    transform: rotate(270deg);
}

编译之后,你会发现在tailwind.css有对应的样式:

// src/styles/tailwind.css

.rotate-0 {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
}

.rotate-90 {
    -webkit-transform: rotate(90deg);
    transform: rotate(90deg);
}

.rotate-180 {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
}

.rotate-270 {
    -webkit-transform: rotate(270deg);
    transform: rotate(270deg);
}

如果你正在做一个响应式的Web应用,或者想令扩展的Tailwind CSS也具有响应式能力,可以在扩展Tailwind CSS的时候使用@responsive指令,比如:

// /src/styles/vendors.css
@responsive { 
    .w-320 {
        width: 320px;
    }
    .w-760 {
        width: 760px;
    }
    .w-1024 {
        width: 1024px;
    }
}

编译出来的代码如下:

// src/styles/tailwind.css
.w-320 {
    width: 320px;
}

.w-760 {
    width: 760px;
}

.w-1024 {
    width: 1024px;
}

@media (min-width: 640px) {
    .sm\:w-320 {
        width: 320px;
    }

    .sm\:w-760 {
        width: 760px;
    }

    .sm\:w-1024 {
        width: 1024px;
    }
}

如果想扩展悬浮或聚焦等状态下的样式,可以使用@variants指令:

@variants hover, focus {
    .button {
        color: #f36;
    }
}

编译出来的结果:

.button {
    color: #f36;
}

.hover\:button:hover {
    color: #f36;
}

.focus\:button:focus {
    color: #f36;
}

@variants指令同样可以放在@responsive,在对应的媒体查询中生成相应的样式代码。

除了在CSS文件中添加自己所需要的实用程序类扩展Tailwind CSS之外,还可以通过Tailwind CSS的插件机制来扩展Tailwind CSS,比如像下面这样:

// tailwind.config.js
module.exports = {
    // a bunch of other tailwind settings
    plugins: [
        function({ addComponents }) {
            const buttons = {
                '.btn': {
                    padding: '.5rem 1rem',
                    borderRadius: '.25rem',
                    fontWeight: '600',
                },
                '.btn-primary': {
                    backgroundColor: '#4299e1',
                    color: '#fff',
                    '&:hover': {
                        backgroundColor: '#3182ce'
                    },
                },
                '.btn-secondary': {
                    backgroundColor: '#667eea',
                    color: '#fff',
                    '&:hover': {
                        backgroundColor: '#5a67d8'
                    },
                },
            }

            addComponents(buttons)
        }
    ]
}

有关于这方面更多的介绍,可以点击这里查阅

在React的项目中使用Tailwind CSS

现在我们对Tailwind CSS有了一个基础性的了解,接下来,我们来看看在React中怎么使用Tailwind CSS来构建页面。

首先清理/src/App.js,删除不必要的代码,你将看到的是一个最干净的代码:

// /src/App.js
import React from 'react';
import './styles/tailwind.css'

function App() {
    return (
        <div className="">
        
        </div>
    );
}

export default App;

接下来,在src/目录下创建一个components目录,并在该目录创建两个组件:HeaderCard

▶ cd src && mkdir components
▶ cd components && mkdir Header Card
▶ cd Header && touch index.js
▶ cd .. && cd Card && touch index.js

项目结构如下:

接下来,先来构建Header组件。在Header/index.js添加所需要的代码:

// /src/components/Header/index.js
import React from 'react';

function Header() {
    return (
        <header className="">
            <h1 className="">
                <svg role="img" aria-hidden="true" focusable="false" height="62.2" width="62.2" version="1.1" viewBox="0 0 62.2 62.2" xmlns="http://www.w3.org/2000/svg" x="0" y="0" xmlSpace="preserve">
                    <path d="M61.207,55.36L47.773,41.925c2.864-4.192,4.543-9.262,4.543-14.712c0-14.424-11.734-26.16-26.159-26.16 C11.734,1.053,0,12.79,0,27.213c0,14.423,11.734,26.158,26.158,26.158c6.53,0,12.502-2.408,17.09-6.379L56.41,60.155 c0.662,0.662,1.529,0.992,2.398,0.992c0.866,0,1.735-0.33,2.397-0.992C62.531,58.833,62.531,56.682,61.207,55.36z M40.921,44.524 c-3.979,3.397-9.133,5.457-14.766,5.457c-12.553,0-22.767-10.215-22.767-22.768c0-12.555,10.214-22.768,22.767-22.768 c12.557,0,22.77,10.213,22.77,22.768c0,4.596-1.373,8.876-3.729,12.46C44.007,41.487,42.566,43.122,40.921,44.524z"/>
                    <path d="M39.08,23.396l-2.409-1.855l-0.653-0.504v-5.79c0-0.819-0.666-1.483-1.484-1.483s-1.482,0.664-1.482,1.483v3.505 L26.9,14.017c-0.436-0.336-1.042-0.336-1.478,0l-9.916,7.634l-2.419,1.862l-2.809,2.163c-0.53,0.408-0.629,1.169-0.221,1.699 c0.408,0.529,1.169,0.629,1.699,0.221l1.33-1.024v12.88c0,0.67,0.543,1.211,1.212,1.211h1.174H37.87 c0.67,0,1.213-0.541,1.213-1.211V26.455l1.479,1.141c0.222,0.17,0.479,0.252,0.736,0.252c0.363,0,0.725-0.162,0.961-0.472 c0.41-0.531,0.312-1.291-0.219-1.7L39.08,23.396z"/>
                </svg>
                <span className="">Tailwind CSS</span>
            </h1>

            <nav role="navigation">
                <ul>
                    <li>
                        <a href="#">Home</a>
                    </li>
                    <li>
                        <a href="#">CSS</a>
                    </li>
                    <li>
                        <a href="#">JavaScript</a>
                    </li>
                    <li>
                        <a href="#">React</a>
                    </li>
                    <li>
                        <a href="#">Vue</a>
                    </li>
                </ul>
            </nav>    
        </header>
    );
}

export default Header;

并在/src/App.js中引入Header组件:

// /src/App.js
import React from 'react';
import Header from './components/Header';
import './styles/tailwind.css'

function App() {
    return (
        <div className="">
        <Header />
        </div>
    );
}

export default App;

你可能看到了,在Header组件中,我们还没有添加任何有关于Tailwind CSS的实用程序类,所以你在浏览器中看到的效果是没有任何样式风格的:

接下就在Header组件的标签元素上添加Tailwind CSS框架中的类:

// src/components/Header/index.js
import React from 'react';

function Header() {
    return (
        <header className="flex items-center bg-gray-900 px-6 py-2 text-white">
            <h1 className="flex items-center mr-6">
                <svg className="fill-current h-8 w-8" role="img" aria-hidden="true" focusable="false" height="62.2" width="62.2" version="1.1" viewBox="0 0 62.2 62.2" xmlns="http://www.w3.org/2000/svg" x="0" y="0" xmlSpace="preserve">...</svg>
                <span className="text-xl ml-2">Tailwind CSS</span>
            </h1>

            <nav role="navigation">
                <ul className="flex items-center text-sm">
                    <li>
                        <a href="#" className="block hover:text-teal-200 p-4">Home</a>
                    </li>
                    <!-- ... -->
                </ul>
            </nav>    
        </header>
    );
}

export default Header;

这个时候,你可以看到有一个带有样式的页头:

我们可以按上面的方式来写Card组件:

// src/components/Card/index.js
import React from 'react';

function Card() {
    return (
        <div className="max-w-sm">
            <div className="rounded overflow-hidden shadow-lg">
                <img
                className="w-full"
                src="https://tailwindcss.com/img/card-top.jpg"
                alt="Sunset in the mountains"
                />
                <div className="px-6 py-4 bg-white">
                <div className="font-bold text-xl mb-2">...</div>
                <p className="text-gray-700 text-sm">...</p>
                </div>
                <div className="px-6 py-4 bg-gray-100">
                    <span className="inline-block bg-gray-300 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2">...</span>
                    <span className="inline-block bg-gray-300 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2">...</span>
                    <span className="inline-block bg-gray-300 rounded-full px-3 py-1 text-sm font-semibold text-gray-700">...</span>
                </div>
            </div>
        </div>
    );
}

export default Card;

App.js中引入Card组件:

// src/App.js
import React from 'react';
import Header from './components/Header';
import Card from './components/Card';
import './styles/tailwind.css'

function App() {
    return (
        <div className="page">
            <Header />
            <main className="flex justify-around h-screen bg-gray-200 py-10 px-6" role="main">
                <Card />
                <Card />
                <Card />
            </main>
        </div>
    );
}

export default App;

此时你看到的效果如下:

整个过程下来,是不是感觉不需要写任何CSS代码就可以构建出想要的UI效果。这也是Tailwind CSS和其他CSS框架不同之处。

小结

在这篇文章中,我们学习了Tailwind CSS的基础知识,同时了解了如何在Reac中使用Tailwind CSS来美化页面。我们还注意到,我们可以更快地设计、开发Web应用程序,因为我们不必再担心编写定制的CSS样式。Web应用程序将变得更易于维护,因为我们不必再担心删除CSS样式。

当然,Tailwind CSS并不是解决所有CSS问题的灵丹妙药,在开发过程中难免是需要添加一些适合业务的类。甚至,你可能在第一次使用Tailwind CSS时,可能会觉得它是违反直觉的(在HTML中标签元素中要添加很多个类名),但是在你决定它是否是适合你的正确方法之前,它是值得坚持的。虽然我不会选择在每个项目中都使用它,但它有明显的好处。如果你对此感兴趣的话,不仿自己一试,只有试过了,才知道是否适合自己。