春节将至,又一年就这样悄悄溜走了。
时值年末,总是会被各种年终总结刷屏。例如与前端开发者息息相关的state of js 2020和state of css 2020调查问卷都相继发出了统计报告,在后者的报告总结中,tailwindcss可以说是异军突起,实力抢眼。
今天就来聊聊,tailwind和它的逆袭之路。
序:tailwind的逆袭之路
在 state of css 2020 的报告数据中,我们会发现 tailwind 的使用满意度非常高,同时使用过 tailwind 的开发者比例在过去的一年了飞速增长。比对积极/消极体验拆分图,tailwind 可以说是“没用过的都想试试,用过的都说好”。
与之对应的,是tailwind背后的 css 原则 atomic css 超越开发者广泛接受的 BEM 命名规则,成为开发者满意度、关注度最高的 css 原则。
why:tailwind缘何而生
tailwind 所关注的问题,可以说是前端开发领域的老大难了:全局 css 冲突。
全局 css 冲突,这一问题随着 SPA 的出现第一次受到了广泛的关注,并引发了一系列的 css 原则和工具的诞生。而随着微前端时代的到来,伴随着新的场景,这一问题再次吸引了更多的关注。
由此诞生的原则和工具包括:
- 以 BEM 命名法为代表,旨在规范 css,减少 class name 冲突的 css 原则:BEM命名规则,ITCSS,OOCSS,atomic css……
- 通过介入编译过程来动态修改 class name 或添加属性,以避免选择器冲突:css in js,scoped css……
- 伴随着微前端出现的上下文隔离方案:web components,iframe……
css 原则
为了理解 tailwind 背后的理念,让我们先来简单了解下几个常见的 css 原则。
BEM 命名规则
BEM 是一种类名命名规则,出现较早,在开发者中有着很高的接受度。BEM 即block__element--modifier
,通过模块作为前缀的命名空间来避免类名冲突:
.dialog__button {}
.dialog__button--confirm {
color: green;
}
BEM作为出现很早的方案,特点是实践非常简单,甚至无需预处理器(当然一般会配合预处理的嵌套功能使用)和属性选择器(彼时甚至可能需要兼容ie6),当然不足之处也很明显:如何命名是软件工程永恒的难题之一,随着项目的增长如何命名模块来避免冲突,以及长到叹息的类名。
ITCSS
ITCSS 的理念是将 css 代码分为7个不同的层级来组织代码:
- settings:设置,设定变量等等
- tools:工具,定义 mixins 等等
- generic:通用,例如 normalize 代码
- base:基础,以标签作为选择器的 css 代码
- object:一些抽象的通用 css 代码
- component:组件层级的 css 代码
- trumps:王牌,唯一允许
!important
的地方
例如:
// settings
$yellow: #ffaa00;
// tools
@mixin sample-mixin() {}
// generic
* { box-sizing: border-box; }
// base
p { line-height: 1.5; }
// object
.o-container { display: block; }
// component
.c-btn { cursor: pointer; }
// trumps
.u-hidden { display: none!important; }
可以将每一层的名字作为文件名的前缀,并配合@import
使用:
@import 'settings.color'
@import 'settings.size'
@import 'tools.gradient'
@import 'generic.normalize'
@import "elements.headings";
@import "elements.links";
@import "objects.animations";
@import "objects.layout";
@import "objects.list";
@import "components.buttons";
@import "components.dialogs";
@import "trumps.utilities";
而在类名命名规则上,则推荐结合了 BEM 的 BEMIT。
OOCSS
OOCSS(面向对象的 CSS)则是借用了面向对象编程中类和继承的概念,并使用驼峰法来命名。例如下面的例子,抽取了metadata
作为基类,并衍生出了三个继承类:
<!-- posts -->
<p class=”metadata postMetaData”>
<a>Author name</a>commented on<a>21-02-2010</a>@
</p>
<!-- comments -->
<p class=”metadata commentMetaData”>
<a>Author name</a>commented on<a>21-02-2010</a>@
</p>
<!-- user info -->
<p class=”metadata useInfoMetaData”>
<a>Author name</a>commented on<a>21-02-2010</a>@
</p>
OOCSS关注的是类名的语义化,以及公用 css 提取。
Atomic css
Atomic css 提倡使用原子化的 css 类来书写代码。其理念包括:
- 工具类(utility classes):atomic css 使用拆分到原子粒度的工具类。例如
.text-right { text-align:: right }
,一个类只对应一条单一的 css。 - 不变(immutable)CSS:不修改css,修改元素的类名。
- breakpoint prefix:atomic css 支持相应式设计,通过将断点作为类名前缀来实现支持。
于是,使用 atomic css 的代码可能是这样的:
<div class="bg-grey text-white text-center grid-12 m:grid-6">
hello atomic css
</div>
也许看到这样的理念,开发者难免会冒出“这是neng啥呢?”的想法。正是这种反直觉的设计理念,以及“用过都说好”的使用体验,结合当下前端的发展趋势,使得 atomic css 以及其理念下的优秀产物 tailwind 在过去的一段时间内迎风起飞,成为前端领域的耀眼明星。
what:tailwind 的理念
工具类优先
tailwind 与相比传统的 css 框架相比,后者通常会抽取公共组件样式,为开发提速的同时,也带来了一定的束缚,而前者则通过工具类的自由组合提供了更大的自由度。
同时,将 css 规则拆分到原子的粒度后,只要事先准备好一套工具类,那么在开发过程中,无论是SPA还是微前端,就不必修改也不必增加新的 css 代码,也不用担心 css 冲突了。
响应式设计
tailwind 支持响应式设计,默认包含四个屏幕宽度断点:
/* Small (sm) */
@media (min-width: 640px) { /* ... */ }
/* Medium (md) */
@media (min-width: 768px) { /* ... */ }
/* Large (lg) */
@media (min-width: 1024px) { /* ... */ }
/* Extra Large (xl) */
@media (min-width: 1280px) { /* ... */ }
tailwind 提倡移动优先的设计理念:
<div class="text-center md:text-left"></div>
组件友好,可定制、可扩展
除了直接使用工具类之外,tailwind 还支持在工具类的基础上抽提可复用的组件。通过其插件化的机制,可以将组件、自定义工具类抽取为 js 插件,在项目间共享。
tailwind 的主题同样是可修改、可扩展的。
how:使用 tailwind
说了这么多,不知道你是否已经跃跃欲试了。tailwind 官网上的教程非常细致,跟着它来了解 tailwind 的方方面面几乎不会遇到任何阻碍。当然,如果你想先对 tailwind 有个初步了解,也可以先看看以下的极简上手指南。
安装使用
这里以 webpack + postcss 为例,当然 tailwind 也可以与其他打包工具及 css 预处理器一起使用,具体可以参见官网。
(目前的 tailwind 需要与 postcss 版本8 一起使用,如果你是通过vue-cli
或是create-react-app
等工具来创建的项目,或许需要先升级一下 postcss 的版本。)
安装:
yarn add tailwindcss
随后,创建一个index.css
文件:
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
通过命令或手动创建tailwind.config.js
:
npx tailwindcss init
配置 postcss-loader:
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
},
...
]
配置postcss.config.js
文件:
module.exports = {
plugins: [
[
"postcss-preset-env",
{},
],
require('tailwindcss'),
require('autoprefixer'),
isProductionMode && require('cssnano')(),
].filter(Boolean),
};
tailwind 会生成大量的工具类,但是我们通常之后使用其中的一小部分,因此生产环境需要配合PurgeCss
移除没用到的类。
编辑tailwind.config.js
:
module.exports = {
purge: {
enabled: isProductionMode,
content: ['./src/**/*.jsx'],
},
};
preflight
tailwind 在normalize.css的基础上建立了基础样式,称为 preflight(预飞、预检,源自飞行器起飞前的检查工作),通过base
引入:
// 芜湖,起飞
@import "tailwindcss/base";
工具类
tailwind 的工具类涵盖了大部分的常规需求,官网上有详细的列表:
- 布局
- 弹性盒子
- 网格布局
- 空间
- 尺寸
- 排版(typology)
- 背景
- 边框
- 表格
- 特效
- 过渡
- 形变
- 交互
- svg
- 可访问性
熟悉这些工具类也许会花上不少时间,不过当你熟悉了 tailwind 的使用,相信你会乐在其中。
// 也许你需要一些时间来习惯长长的类名
return (
<div className="bg-yellow-300 text-white text-center p-2 mt-4">
淡黄的背景,雪白的文字
</div>
);
编辑器插件
为了方便使用,编辑器插件是必不可少的,如果你在使用 vscode,那么 tailwind css intellisense 便是一个不错的选择:
- 自动补全
- lint
- 悬停预览:当鼠标悬停在类名上时,展示其对应的 css
例如:
.text-white {
--tw-text-opacity: 1;
color: rgba(255, 255, 255, var(--tw-text-opacity));
}
.mt-4 {
margin-top: 1rem/* 16px */;
}
响应式
tailwind 预设了四个屏幕宽度断点:
- sm: min-width: 640px
- md: min-width: 768px
- lg: min-width: 1024px
- xl: min-width: 1280px
使用时,通过[断点]:[工具类]
的方式设置不同响应式的样式。建议遵从移动优先的理念,即先设置基础样式,在用大屏下的样式去覆盖,例如:
<div class="w-16 md:w-32 lg:w-48">mobile first</div>
伪类(variants)
伪类同样通过[伪类]:[工具类]
的方式使用,例如:
class="bg-teal-500 hover:bg-teal-600 focus:outline-none"
// 同时设置响应式和伪类:响应式:伪类:样式
class="sm:hover:bg-green-600"
伪类包括:
- hover
- focus
- active
- disabled
- visited
- child
- last
- odd
- even
- group & group-hover
- group & group-focus
- focus-within
组件提取
tailwind 提供了@apply
,以实现组件的提取功能:
// jsx
return <div className="btn btn--blue">btn</div>
// index.css
.btn {
@apply font-bold py-2 px-4 rounded;
}
.btn-blue {
@apply bg-blue-500 text-white;
}
.btn-blue:hover {
@apply bg-blue-700;
}
为自定义 css 生成前缀
tailwind 提供了@responsive
以及@variants
来为我们自己编写的 css 生成前缀:
return (
<>
<div className="xrotate-0 hover:xrotate-90"</div>
<div className="xrotate-0 md:xrotate-90"</div>
<div className="xrotate-0 md:hover:xrotate-90"</div>
</>
);
@responsive {
@variants hover, focus {
.xrotate-0 {
transform: rotate(0deg);
}
.xrotate-90 {
transform: rotate(90deg);
}
.xrotate-180 {
transform: rotate(180deg);
}
.xrotate-270 {
transform: rotate(270deg);
}
}
}
css 文件结构
tailwind 建议以一定的顺序在 css 文件中引入 tailwind、定义全局样式、抽取组件、编写自定义工具类:
// 引入基础库
@tailwind base;
// 自定义全局样式
h1 {
@apply text-2xl;
}
a {
@apply text-blue-600 underline;
}
// 字体
@font-face {
font-family: Proxima Nova;
font-weight: 400;
src: url(/fonts/proxima-nova/400-regular.woff) format("woff");
}
//
@tailwind components;
// 自定义组件
.btn {
@apply font-bold py-2 px-4 rounded;
}
.btn-blue {
@apply bg-blue-500 text-white;
}
//
@tailwind utilities;
// 自定义工具类
@responsive { /* 可选 */
@variants hover, focus { /* 可选 */
.xrotate-0 {
transform: rotate(0deg);
}
}
}
配置文件与主题
配置文件允许我们编辑和扩展主题、修改伪类的生成规则、引入插件等等:
module.exports = {
theme: {},
variants: {},
plugins: [],
}
关于主题的内容,大家可以参见官方文档,这里先不介绍了
插件机制
tailwind 的插件机制,提供了可复用的扩展组件和工具类的方式:
// tailwind.config.js
module.exports = {
theme: {
// ...
// 使用 gradients 插件
gradients: theme => ({
'blue-green': [theme('colors.blue.500'), theme('colors.green.500')],
'purple-blue': [theme('colors.purple.500'), theme('colors.blue.500')],
}),
},
variants: {
// ...
},
plugins: [
// 注册插件
require('./twplugins/utilities/gradients'),
require('./twplugins/comps/compA')
],
};
// twplugins/utilities/gradients.js
module.exports = plugin(({ addUtilities, e, theme, variants }) => {
const gradients = theme('gradients', {});
const gradientVariants = variants('gradients', []);
const utilities = _.map(gradients, ([start, end], name) => ({
[`.bg-gradient-${e(name)}`]: {
backgroundImage: `linear-gradient(to right, ${start}, ${end})`
}
}));
addUtilities(utilities, gradientVariants);
});
// twplugins/comps/compA.js
module.exports = plugin(({ addComponents, config }) => {
const comps = {
'.comp-a': {
padding: '.5rem 1rem',
borderRadius: '.25rem',
fontWeight: '600',
},
'.comp-a-primary': {
backgroundColor: config('theme.colors.primary'),
color: '#fff',
},
'.comp-a-secondary': {
backgroundColor: config('theme.colors.secondary'),
color: '#fff',
},
}
addComponents(comps);
});
最后
看了以上介绍,你心动了没?快开始使用tailwindcss开发你的前端项目吧~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!