tailwindcss
tailwindcss 这东西,并不能将当作替代 css 的东西来看。其主要作用统一项目 css 样式,不搞太多的自定义样式,在需要自定义的场景下大可以直接使用 css 来写,这俩是不冲突的。
原谅我一直都接受不了 tailwindcss 这个东西,目前只能作为规范化工具来使用了。
编译机制
有个常见误区,也就是 tail 是内置了大量的原子类用来实现现有的工作方式。其实并不是这样,tail 工作原理是在构建时扫描代码中的字符串,来生成对应的 css。
因此对于如下情况,tail 并不会工作
1 | <div :class="`columns-${ columnNum }`"></div> |
tail 无法识别动态的字符串,你必须要在代码中使用完全静态的类名,例如下面这种 tail 是可以正常识别的:
1 | <div :class="[ |
父子节点
tail 支持通过 group 类名来指定父节点,然后便可以通过诸如 group-hover:xxx 的方式来在特定场景下控制子节点:
1 | <div class="group"> |
上面这个案例意思就是,当 div 被 hover 时,放大 img 标签为 1.1 倍
命名 group
group 也可以命名,格式为 group/<命名>,对应的触发类名格式也相应变为 group-hover/<命名>。例如:
1 | <div class="group/img"> |
不建议在整合样式里使用 group,有一定可能会出现样式不生效的情况。建议照常使用 css 的 hover
整合样式
把类名全都一股脑塞在 html 里显然是极度恶心的,tail 提供了类名整合的方式,通过 @apply 即可实现。例如现在有如下 vue 代码:
1 | <template> |
使用 @apply 整合后的效果如下:
1 | <template> |
新版 tail 使用 apply 时必须要手动引入 tail 样式库,即
@reference "tailwindcss";这一行不能省略,否则会报错
且该行后面的;千万不要省略,否则会导致后面紧跟的第一段样式无法被 tail 正确解析。造成一种“只有第一段无效,其他都有效”的诡异现象。
spacing 宽度
tail 通常使用一些简写+数字来设置 css 样式宽度,如
1 | w-4 // width |
这套是 tailwindcss 默认的 spacing 方案,该方案的数字一般指代 0.25rem 的倍数关系,因此上述的三个样式可以翻译为:
1 | width: 1rem; |
又因为 rem 一般等于 16px,因此上述三个样式也可以翻译为:
1 | width: 16px; |
这样看下来,只要把 spacing 数字乘以 4 就可以得到对应的 px 值了。
任意值语法
如果无法接受 tail 的预设方案,也存在任意值写法:
1 | w-[10px] // width: 10px; |
不能出现的字符
任意值语法中,只有空格是不能出现的,需要使用 _ 特殊符号代替,其他的都可以直接写
1 | shadow-[0_2px_10px_rgba(0,0,0,0.2)] // box-shadow: 0 2px 10px rgba(0,0,0,0.2); |
使用 css 变量
1 | bg-[var(--ui-bg)] // background-color: var(--ui-bg); |
带上样式名
不想记 tail 类名的话,也可以直接把样式名写到任意值语法里
1 | [column-fill:_balance] // column-fill: balance |
css 选择器
任意值语法也可以控制 css 选择器:
1 | <ul class="[&_li]:bg-red-500"></ul> |
_ 代表空格,& 代表当前元素。上面这种写法等价于:
1 | ul li { |
类似还有其他选择器写法,参考表格:
| 写法 | 含义 |
|---|---|
[&_li] |
所有后代 li |
[&>li] |
直接子 li |
[&_p] |
所有后代 p |
[&>*] |
所有直接子元素 |
[&_a:hover] |
所有 a:hover |
important 权重
在类名后追加 ! 即可提升样式权重,效果就是 css 的 !important,例如:
1 | relative! // position: relative !important; |
一些复合类名,添加 ! 后他下面的所有样式都会被追加 !important,例如 truncate:
1 | truncate! |
渲染结果
1 | .truncate\! { |
四值类名
一些像 margin、padding 这种支持四个方向的样式,tail 提供的类名也有对应规律:
1 | m-4 // margin: 1rem; |
即:x 表示左右,y 表示上下,t 表示上,r 表示右,b 表示下,l 表示左,负号表示取反。
阴影/描边
tail 中控制 box-shadow 的类名为 shadow-xxx。但细心的话可以看到:当指着 shadow 类名时,编辑器给出的提示是 --tw-shadow:
这是因为 tail 实际上对 box-shadow 的操作是下面的 css 代码:
1 | box-shadow: var(--tw-inset-shadow), |
tail 实现的一些样式会用到相同的 css 属性,为了避免互相覆盖,便使用了这种变量名的办法,即这里的 shadow 只负责控制 tw-shadow 变量。
描边
在这里与 shadow 公用 box-shadow 的是 ring,即外发光描边。这是一个 tail 自创的属性,旨在实现轮廓的效果。
之所以通过 box-shadow 来操作,是因为其他可实现类似效果的属性有各自的痛点:
- border: 会影响盒模型宽高,影响布局,导致页面跳动,我们通常都不得追加一条
box-sizing: border-box;,但未显示设置宽高的盒子依然会有这个问题。 - outline: 不能设置圆角、不支持偏移控制,无法实现复杂效果
ring 存在两种模式,这两种可以共存,即常规和offset:
- 常规:即最外层描边,宽度使用
ring-数字(单位 px)设置,颜色使用ring-颜色-颜色比重设置 - offset: 内层描边,宽度使用
ring-offset-数字(单位 px)设置,颜色使用ring-offset-颜色-颜色比重设置
当两者共存时,结果就是常规描边在最外层,内层是 offset,如下面代码效果就是:8px 厚度的淡黄色描边 + 外层 2px 厚度的橙色描边
1 | <div class="ring-2 ring-yellow-600 ring-offset-8 ring-offset-yellow-200"></div> |
一些常用类名
space-y-4
等价为如下 css(不严谨,因为这个的实现其实比较麻烦),即相邻子元素之间存在 1rem 的间距(除第一个元素)
1 | & > * + * { |
横向版本即 space-x-4
truncate
起到单行省略作用,即如下 css
1 | .truncate { |
line-clamp-2
起到多行省略作用,即如下 css
1 | .line-clamp-2 { |