CSS(Cascading Style Sheet)
CSS的主要功能是用来指定HTML文档的样式(或许也可以应用于其他DOM文档)。
一个HTML文档可以看作一颗DOM树,由不同的DOM节点组成。这些个DOM节点代表的是HTML元素,比如<a>
, <body>
之类的。每个HTML元素都带有若干属性,可以用来指定HTML元素的样式。
在CSS之前,HTML元素的样式属性是直接书写在HTML元素标签上的。这种做法可扩展性和可维护性都比较差。比如,这种方式难以解决一个看似简单的问题:“如果让多个HTML元素具有相同的样式属性集合?”。 为此,很自然需要一种机制,来为多个HTML元素指定相同的样式集合。一个很自然的解决方案是给一个样式集合起一个名字,这样样式集合就成为了一个样式类(class)。一个样式类可以应用到不同的元素上。
不过样式类的到HTML元素可能会遇到一个技术问题:万一样式类中带有的样式属性在某个HTML元素上不被支持怎么办?这时候一个简单的处理办法可能是直接在该HTML元素上忽略这个样式属性。
有了样式类的概念,一个样式类可以应用到多个HTML元素,那么让一个HTML元素可以应用多个样式类也是非常自然的事情。技术上,只要遵循后来居上的原则,让后来的样式类中的属性覆盖先来的样式类中的属性,就不存在冲突问题。
在样式类的应用上,CSS还有许多绝活。比如,CSS可以通过选择器(selector)来灵活地指定样式类该应用在什么元素集合上。CSS还带有伪类(pseudo class)功能,可能用来增加更多应用的场景。比如:hover
这个伪类可以增加交互式性,让鼠标移到HTML元素上的时候触发不同的样式。
作为一种样式描述语言,CSS基本上是静态的,但是也具有一部分计算能力,比如其calc()
函数可以在指定样式属性值的时候进行一些计算。此外,最新版本的CSS还支持CSS Custom Properties,可以在CSS中使用类似变量的功能。
但是CSS毕竟不是一门编程语言,如果需要更大的计算灵活性,则需要一些预处理器,比如SASS,在生成CSS之前做一些预处理。
PostCSS
PostCSS是一个CSS处理工具。和前面提到的SASS不同,PostCSS并不是一个预处理器,它的处理CSS的思路有点模仿浏览器对CSS的处理,先对解析CSS样式表,并生成相应的AST(抽象语法树);不过PostCSS并不像浏览器那样直接将AST应用到HTML文档中,而是允许插件对生成的AST进行修改,最后PostCSS把修改后的AST再合成CSS样式表以备使用。
PostCSS Architecture描述了PostCSS的架构;PostCSS Plugins里面列举了许多插件。PostCSS的API可以在http://api.postcss.org/查看。
类似的工具其实不止PostCSS一家,其他的可以参考PostCSS Benchmarks中的parsers一节。
TailwindCSS
看TailwindCSS的设计,它提供了分类,螺丝刀,钉子。
安装tailwindcss cli:
yarn global add tailwindcss
独立的CLI可以通过scoop安装:
scoop install tailwindcss
,竟有36MB之巨。
然后就可以使用tailwindcss或者tailwind命令。
tailwind init
可以创建一个配置文件tailwind.config.js
,
例如:
module.exports = {
content: ["./src/**/*.{html,js}"],
theme: {
extend: {},
},
plugins: [
// 示例插件
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
]
}
说明点:
-
如果content指向的文件中没有使用的到tailwind的css标类,默认不会带到生成的css文件中
@tailwind base;
指示的内容除外- 必须指定base,关掉的话,需要在corePlugins吧preflight关掉
- 看来是因为3.0引入了JIT:https://tailwindcss.com/docs/upgrade-guide#migrating-to-the-jit-engine
- 不使用PurgeCSS了
- 关掉jit的话,参考
- https://github.com/tailwindlabs/tailwindcss/discussions/6347
- https://github.com/tailwindlabs/tailwindcss/discussions/6256
- 也就是说JIT是默认开启的,可以通过safelist来强制生成所需的类,参考https://tailwindcss.com/docs/content-configuration#safelisting-classes
saftlist: [ { pattern: /.*/, variants: ['lg', 'hover', 'focus', 'lg:hover'], }, ]
-
tailwindcss init --full
可以初始化一个更完整的配置文件。
两个相关命令:
tailwind -i input.css -o output.css --watch
tailwind -i input.css -o output.css --minify
通过-c
选项可以指定配置文件,而不是使用默认的tailwind.config.js
。
corePlugins
配置分组可以允许禁用某些核心功能:
module.exports = {
corePlugins: {
float: false,
objectFit: false,
objectPosition: false,
}
}
上面是指定哪些核心功能要关闭,如果要指定白名单,则使用下面的方式:
module.exports = {
corePlugins: [
'margin',
'padding',
'backgroundColor',
// ...
]
}
多配置的实现有几种方式。
可以在css文件中指定配置文件:
@config "./tailwind.site.config.js";
@tailwind base;
@tailwind components;
@tailwind utilities;
可以在js中编程使用:
import resolveConfig from 'tailwindcss/resolveConfig'
import tailwindConfig from './tailwind.config.js'
const fullConfig = resolveConfig(tailwindConfig)
如果在给配置加上typescript信息,可以:
/** @type {import('tailwindcss').Config} */
module.exports = {
...
}
观感
tailwindcss给人的感觉,有点类似于汇编之于机器码。像C/C++这种程序语言,一般先编译成汇编语言,然后再通过汇编器转化成机器码。
在CSS的语言框架内,机器码可以看出是CSS所给出的各种辖属,比如style="color: blue"
这种随行的CSS,其中用到color辖属。
这样的用法缺乏扩展性,因为在不同主题、或不同场景下,需要设置不同的color,直接写死导致难以修改。
很多CSS框架的做法是指定一个CSS标类,用于描述语言,比如用一个.btn
,表示一个按键,此标类下的HTML元素都具有按键的语义。
Tailwind则是在CSS辖属和用于表示语义的.btn
们之间找了一个平衡,用CSS标类表示一个原子基本的语义,然后.btn
可以被拆散成了多个原子语义。
原子语义的好处是它更稳定,组合起来更方便。可以用原子语义组合成目标语义。如果工程中需要经常变动和增删目标语义的话,会更方便。
原子语义也是用CSS的标类来指定的,这利用了HTML元素上可以指定多个CSS标类的特性。
原子语义的缺点是它必须足够多,足够庞杂,才能对目标语义形成足够多的支撑。这样一来,存放原子语义的CSS文件就会变得非常大。 Tailwind采用的策略是按需裁剪,也就是把没有用到的原子语义给剔除掉。2.x版本中,Tailwind使用的是PurgeCSS来裁剪,3.x版本中,Tailwind自研了JIT功能,不再依赖第三方。
我觉得这个方向应该能更进一步,原子语义还是比较适合范化和重构操作的,如果有IDE的支持的话,会如虎添翼。简单地说,IDE可以对元素上指定的原子语义CSS标类进行排序,或将其提取生成更高一级语义CSS标类。
参考
- tailwind playground: https://play.tailwindcss.com/
- https://tailwindcss.com/docs/configuration
- https://github.com/tailwindlabs/tailwindcss/blob/master/stubs/defaultConfig.stub.js
- tailwind UI
- https://tailwindcss.com/blog/tailwindcss-v3#just-in-time-all-the-time
其他参考
CSS Custom Properties相关
-
https://www.smashingmagazine.com/2018/05/css-custom-properties-strategy-guide/
-
https://www.toptal.com/front-end/dynamic-css-with-custom-properties
-
https://www.sitepoint.com/css-theming-custom-properties-javascript/
-
https://css-tricks.com/building-skeleton-screens-css-custom-properties/
-
https://www.sitepoint.com/css-theming-custom-properties-javascript/
-
Import CSS Selector Styles in Another Selector? (NOT @import)
UnoCss的概念有点类似于tailwind,但是手段有所不同。
(本篇完)
2023-01-25更新:Next.js
Get started with Tailwind CSS有针对各个流行框架的安装教程。
- Install Tailwind CSS with Next.js
- Create your project
npx create-next-app@latest my-project --typescript --eslint
cd my-project
- Install Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
- Configure your template paths
- 对tailwind.config.js做相应修改
- Add the Tailwind directives to your CSS
- 在globals.css中添加相应的@tailwind指示
- 这样就可以在jsx中使用tailwind css了
- 例子:
<h1 className="text-3xl font-bold underline">
- 例子:
- Create your project
(更新完)
2023-01-26更新:DaisyUI
(更新待续)