简短的概括:
发现问题:项目中css代码痛点
.mock {
margin: auto;
font-size: 16px;
// ...
}
<div class='mock'>mock</div>
以上代码就是举个例子,大部分情况应该都是写一个类,然后整一堆样式进去。这种方式写多了以后,会感受到一些痛点,比如说:
1) 取名困难,节点结构一多,取名真的是个难事。当然了,我们可以用一些规范或者选择器的方式去规避一些取名问题。
2) 需要用 JS 控制样式的时候又得多写一个类,尤其交互多的场景。
3) 组件复用大家都懂,但是样式复用少之又少,这样就造成了冗余代码变多。
4) 全局污染,这个其实现在挺多工具都能帮我们自动解决了。
5) 死代码问题。JS 我们通过 tree shaking 的方式去除用不到的代码减少文件体积,但是 CSS 该怎么去除?尤其当项目变大以后,无用 CSS 代码总会出现。
6) 样式表的插入顺序影响了 CSS 到底是如何生效的。
一、Tailwind CSS 介绍
Tailwind 能够快速将样式添加到 HTML 元素中,并提供了大量的开箱即用的设计样式。
tailwindcss 基于比组件更小、更灵活的工具类思想的 CSS 框架。这个思想简单来说就是用 class 保证灵活、便于自定义组件,而不是在组件基础上实现个性化。
官网:https://www.tailwindcss.cn/
如果你从来没见过 Tailwind 的实际应用,可以看这个:
<div class="bg-gray-100 rounded-xl p-8">Hello World</div>
这里的类名就反映了 Tailwind 的定义:一个包含多个预定义类(所谓的工具类)的集合。你并不需要编写基础的 CSS 样式规则,只需要直接在 HTML 中应用已经事先定义好的类名。
这样的类名还有很多。下面这个列表展示了部分类别和对应的例子:
1)背景 (bg-gray-200, bg-gradient-to-bl)
2)弹性布局 (flex-1, flex-row)
3)网格布局 (grid-cols-1, col-span-4)
4)内边距 (p-0, p-1)
5)尺寸 (w-1, h-1)
开发大型应用的时候,每一个 HTML 元素都充斥着一大堆 Tailwind 的工具类名。
<div class="sm:w-4 md:w-6 lg:w-10 xl:w-full sm:text-sm md:text-base lg:text-base xl:text-2xl flex-1 sm:flex-none bg-black sm:bg-white rounded-md sm:rounded-none">
hello world
</div>
问题:
要怎么组织这些类名呢?也许我们要创建并遵循某个排序规则。
解决方案:
部分 HTML 元素会使用非常多的样式,这种情况下应该考虑将样式与 HTML 标签进行分离,单独放到某个文件里。这样,我们就可以组织样式并增强其可读性。你不能把 CSS 的所有功能”塞到“ class 这一个 HTML 标签属性里,Tailwind 也不能。这样做只会让 HTML 结构越发臃肿。
@apply
针对上面提到的问题,Tailwind 允许我们在单个 CSS 文件中使用它们的类名:
.header {
@apply bg-red-200 w-4 text-gray-400 rounded-sm border-2;
}
比如说项目中的按钮都是存在通用的圆角、内边距、字体等,这样我们就可以封装出这样一个类:
.btn {
@apply p-8 rounded-xl font-semibold;
}
二、使用 Tailwind CSS 的理由
1、超小的文件尺寸 = 令人难以置信的性能
在开发模式下,Tailwind的输出尺寸非常大。这是设计使然:在此阶段生成每个可能的类,因此当你想要使用某些东西时,无需等待完成构建的过程。
但是,一旦Tailwind CSS进入生产模式,就会清除所有未与PurgeCSS工具一起使用的类。这是通过在项目文件中搜索类的名称来实现的,只保留那些使用过的。你可以在purge数组中的tailwind.config.js中配置将搜索哪些文件路径。
// tailwind.config.js
module.exports = {
purge: [
"./src/**/*.html",
"./src/**/*.vue",
'./src/**/*.js'
],
theme: {},
variants: {},
plugins: [],
}
2、原型和快速构建
使用常规SCSS,需要为页面上的每个元素编写自定义类。这样虽然可以提供更好的控制,但编写自定义类需要花费大量时间:你必须在HTML中添加类,然后在CSS中创建,再以长格式写出每个属性。你必须等待CSS构建后才能看到结果——并且,如果你需要进行更多更改,则每次都需要重新构建,这可能会花费几秒钟时间并中断你的流程。
Tailwind CSS取消了这些额外的步骤,并在为元素设置样式时提供了简单、爽快的开发体验。可以看到想要设置样式的元素,使用简写方式添加需要的属性,不需要等待CSS文件束就能很快出现改变。因此只要专注于一个地方即可,不用频繁切换到不同的文件,整个过程感觉很流畅。
<div class="bg-white rounded p-4">
<h1 class="text-24 font-heading underline">
Foobar
</h1>
<p class="text-16 font-body>
Hello world!
</p>
</div>
3、消除范围泄漏
人们喜欢BEM以及它能在今天如此流行的原因是,命名系统类的构建是为了表示组件的结构。在使其易于阅读和理解的同时,开发人员还受益于这种结构:由于布局易于理解,因而可以在不使用CSS选择器的情况下编写类。如下:
// this
.block {
&__element { ... }
&__element--modifier { ... }
}
// not this
.block {
& > .element {
&.modifier { ... }
}
}
CSS选择器的问题在于它们给CSS带来了复杂性:组件变得非常依赖于特定的HTML结构。由于通用CSS类,例如.container,可以重复多次,所以使用这些名称可能会导致重叠,因此更改一个类将影响许多其他的类。这是我们使用BEM的主要原因之一,因为它使得结构清晰,并将每个类扁平化到顶级范围,这样就不会互相依赖。如果没有像这样的CSS方法,那么开发工作可能会让人头疼,并且其简单性意味着其他人可以更容易地理解它。
三、Tailwindcss 为何大受欢迎
NPM.DEVTOOL 中 tailwind 标签大全
地址:https://npm.devtool.tech/tailwindcss
现在项目开发用的 TailwindCSS,在这里谈一点感受,TailwindCSS 因为一个 class 代表一个 CSS 属性这种原子化 CSS (Atomic CSS),这种细粒度的 CSS 方案备受争议。
1、四种粒度
<div style="{ borderRadius: '0.5rem', padding: '1rem' }"> Click </div>
<div class="rounded-lg p-4"> Click </div>
<div class="button"> Click </div>
<Button> Click </Button>
越往下封装的粒度就越大,越抽象,灵活性就越低,但是灵活性往往是和开发工作量成反比的,灵活性越高也就意味着更多的工作需要开发者自己去处理,如何平衡开发工作量与灵活度之间的关系就显得尤为重要。
因为这涉及到css库的选择,其中BootStrap库更多的是提供颗粒度3的形式,给定一个固定的样式,开发者需要自定义样式的话必须去重写样式,而tailwind则是提供颗粒度2形式的原子样式,更多的是提供一种规范,然后将更大的自由度交由开发者,由开发者来进行样式的组装。
2、一些问题的解答
Tailwindcss 为啥受欢迎,无非是更好用的原子化的 CSS。在国外如火如荼,但是在国内论坛上争议很大,前几天看的前端大佬博客上写了一篇关于 Tailwindcss 的文章,但是底下评论很多了各种问题,总结一下
Q1: tailwind的写法和行内 CSS 有何区别,不就少写几个字吗?
大部分人的想法应该是这样的: 仅仅对于 text-center 而言,虽然提供了些许方便,但是不足以拉开差距。
如果说它仅仅是简单的原子化 CSS,好用却不亮眼。但是它却不仅仅止于此。
1. 方便性: text-center、grid-cols-3
或许一个 text-center 不足以使你觉得提供了多大的方便性,但对于一个三等分的 Grid 属性来说,一个 grid-cols-3 和 shadow 绝对方便。
.grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
2. 语义化: text-lg、text-white、ring、animate-spin`
text-lg,一个较大字体,如果设置行内样式,肯定有诸多麻烦的事: 我想设计一个较大的字体,那我应该设计多大尺寸、使用什么单位。
同样还有:
text-white: 白色的色值是哪个来着?
ring: 我想给这个按钮加一个圈圈?
animate-spin: 怎么做一个动画?
3. 响应式:
先来看一个在工作中会遇到的响应式布局问题,这也是我上一次在头条面试时的一道题目
响应式布局,一大堆子元素,在大屏幕三等分,中等屏幕二等分,小屏幕一等分?
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
通过 grid 布局很容易实现,但未免繁琐
@media (min-width: 1024px) {
.container {
grid-template-columns: repeat(3,minmax(0,1fr));
}
}
@media (min-width: 768px) {
.container {
grid-template-columns: repeat(2,minmax(0,1fr));
}
}
.conainer {
display: grid;
gap: 1rem;
}
那使用 tailwind 呢? 只要一行,就问你高效不高效。
4. 修饰符
把修饰符,如各种伪类、暗黑模式、响应式设计至于前缀的设计简直深得我心。
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"></div>
Q2: 既然 TailwindCSS 这么好用,那岂不是可以摆脱手写 CSS 了
很遗憾,不能。不过虽然你无法摆脱手写 CSS,但是你基本上也写不了几行,说以下几种很常用的情况。
1. 复杂选择器
当父级元素鼠标悬浮时的,子级元素的样式控制
.container:hover .item {
}
2. CSS function
.body {
height: calc(100vh - 6rem)
}
3. 多种属性复用
.item {
@apply p-2 border-b flex justify-between font-mono;
}
Q3: 造成新的记忆负担
这个问题就仁者见仁智者见智了,在 Vue 的 template 语法中也经常出现此类问题,很多人会对一些命名上的约定,特别是自己不太喜欢的约定天然排斥,这也无可厚非。
在初期确实会一边开发网页,一边瞅着文档全局搜索: TailwindCSS 属性查找,现在借助浏览器插件及熟能生巧的经验已经不太需要翻文档了。
1. Tailwind CSS IntelliSense (vscode)
智能补全
代码提示
初期经常花时间翻文档而不手写 CSS,而其中的原因不外乎两个:
1、多写几个字母,确实有点嫌麻烦,有这时间还不如看看文档,全局搜索下也不费事;
2、自己设置一个 fontSize,padding、margin 实在不知道设置多少尺寸,tailwindcss 有较大的约束;
过了多久就会觉得: 嗯,真香。
四、Tailwindcss 项目实践
原本传统的写法是定义一个类,然后写上需要的样式:
.class1 {
font-size: 18px;
margin: 10px;
}
.class2 {
font-size: 16px;
color: red;
margin: 10px;
}
这种写法是存在一部分样式重复的,换成 Atom CSS 就能减少一部分代码的冗余。
把 CSS 当成组件来写。大家乍一看 tailwindcss 官网肯定会觉得我在 HTML 里写个样式要敲那么多类不好吧。
<figure class="md:flex bg-gray-100 rounded-xl p-8 md:p-0">
<img class="w-32 h-32 md:w-48 md:h-auto md:rounded-none rounded-full mx-auto" src="/sarah-dayan.jpg" alt="" width="384" height="512">
<div class="pt-6 md:p-8 text-center md:text-left space-y-4">
<blockquote>
<p class="text-lg font-semibold">
“Tailwind CSS is the only framework that I've seen scale
on large teams. It’s easy to customize, adapts to any design,
and the build size is tiny.”
</p>
</blockquote>
<figcaption class="font-medium">
<div class="text-cyan-600">
Sarah Dayan
</div>
<div class="text-gray-500">
Staff Engineer, Algolia
</div>
</figcaption>
</div>
</figure>
其实我们是可以利用 Atom CSS 一次只干一件事的特性,将这些类随意组装成我们想要的类,这样就可以提供出来一个更上层的通用样式来复用。
tailwind.confing.js 配置文件
/**
* 定制配置
* 默认配置请参考 https://unpkg.com/browse/tailwindcss@2.2.6/stubs/defaultConfig.stub.js
*/
module.exports = {
purge: [
"./src/**/*.html",
"./src/**/*.vue",
'./src/**/*.jsx'
],
theme: {
extend: {
fontFamily: {
sans: ["Inter", "Roboto", '"Segoe UI"'],
dincond: ["DINCond-Black"]
},
fontSize: {
'2.5': '0.625rem', // 10px
'3': '0.375rem', // 12px
'5.5xl': '3.25rem', // 52px
'4.5xl': '2.5rem', //40px
},
width: {
'4.5': '1.125rem', //18px
'10.5': '2.65rem', //42px
'15': '3.75rem', // 60px
'18': '4.5rem', // 74px
'18.5': '4.625rem', // 74px
'23': '5.75rem' // 92px
},
lineHeight: {
'12': '3rem', // 48px
'15': '3.875rem', // 62px
'16': '4rem', //64px
'14': '3.5rem', //56px
"18" : "4.625rem" //74px
},
padding: {
'0.5': '0.125rem', // 2px
'5.5': '1.375rem', // 22px
'4.5': '1.125rem', //18px
'0.75': '0.1875rem', //3px
'7.5': '1.875rem' //30px
},
paddingBottom:{
'4.5': '1.375rem' //22px
},
margin: {
'4.5': '1.125rem', //18px
'15': '3.75rem', // 60px
'21.25': '5.3125rem', // 85px
'11.5': '2.875rem', // 46px
'19': '4.75rem', //76px
},
marginTop: {
'6.5': '1.625rem', // 26px
},
spacing: {
'3.5': '0.875rem', // 14px
'7.5': '1.875rem', //30px
'9.5': '2.375rem', // 38px
// '15': '3.375rem', // 54px
'11.5': '2.875rem', // 46px
'23': '5.75rem', // 92px
'28': '7rem', // 112px
'98': '39rem', // 624px
},
height: {
'0.25': '0.0625rem', //1px
'0.75': '0.1875rem', // 3px
'14': '3.5rem', // 56px
'10.5': '2.65rem' //42px
},
backgroundColor: {
'primary-a100': 'rgba(43, 121, 255, 0.1)',
},
borderRadius: {
'5.5': '1.375rem'
}, //22px
zIndex: {
'6': 6 // z-index: 6
},
screens:{
'3xl': '1664px',
'4xl': '1792px'
},
scale: {
'85': '.85', // 0.85rem
}
}
},
plugins: [
require("tailwindcss-theming")({
variants: {
light: true
}
})
]
};
至此,我们已经了解了什么是 Tailwind CSS?如何使用 Tailwind CSS?Tailwind CSS 定制以及插件的使用,相信大家对Tailwind CSS已经有一个全面的认识。