告别 Tailwind,学会结构化我的 CSS
你好!8 年前,我曾兴奋地写过一篇关于发现 Tailwind 的文章。
那时候我完全不知道该如何组织自己的 CSS 代码,在一团糟和 Tailwind 之间做选择时,我非常乐意选择 Tailwind。它帮我做了好多小网站!
在过去一周左右的时间里,我把几个网站从 Tailwind 迁移到了更语义化的 HTML + 原生 CSS,这个过程非常有趣、也非常有意思,所以我想分享一下学到的东西!
和往常一样,我不是全职的前端开发者,所以这些年来我对 CSS 的学习一直是断断续续的。
原来 Tailwind 教会了我很多
当我开始思考如何组织 CSS 时,一开始有点畏难:我不太擅长组织 CSS!但后来我开始阅读一些讨论如何组织 CSS 的博文(比如A whole cascade of layers 或How I write CSS in 2024),我意识到几件事:
- 每个 CSS 代码库都有很多不同的关注点(布局!字体!颜色!通用组件!)
- 为每一类关注点都建立一套系统或规范来管理是非常有用的,否则就会陷入混乱
- Tailwind 已经为其中一些方面提供了系统,而我已经了解那些系统了!也许我可以模仿我喜欢的那些系统!
比如,Tailwind 有:
接下来要讨论的几个系统
接下来我会谈谈 CSS 代码库的几个方面,以及到目前为止我对每一部分想施加怎样的规则。其中一些是从 Tailwind 抄来的,有些则不是。
- 重置
- 组件
- 颜色
- 字体大小
- 工具类
- 基础样式
- 间距
- 响应式设计
- 构建系统
1. 重置
我只是把 Tailwind 的“preflight styles”抄了过来,做法是打开 tailwind.css 复制前 200 行左右。
我发现随着时间的推移,我已经和 Tailwind 的 CSS 重置建立了某种联系,例如 Tailwind 会给每个元素设置 box-sizing: border-box(这意味着元素的宽度会包含其内边距):
* { box-sizing: border-box; }我想,如果要我不用这些重置去写 CSS,会真的很不适应,而且我敢肯定 Tailwind 重置里还有很多其他东西(比如 html {line-height: 1.5;})是我已经下意识习惯了、甚至没有意识到它们存在的。
2. 组件
接下来的这部分是 CSS 的主体!
这里的想法是按“组件”来组织 CSS,这在精神上和 Vue 或 React 组件有些相似。(尽管网站里可能根本没有任何 Javascript)
基本上思路是:
- 每个“组件”都有一个唯一的类
- 一个组件的 CSS 永远不会覆盖另一个组件的 CSS
- 每个组件都有自己独立的 CSS 文件
所以编辑一个组件的 CSS 就不会莫名其妙地弄坏另一个组件。而且可能有 80% 我真正想改的 CSS 都在各个组件文件里,所以如果我在编辑一个 100 行的组件,我只需要考虑这 100 行。对我来说这样思考要容易得多。
例如,下面这段 HTML 可能就是 .zine 这个“组件”。
<figure class="zine horizontal">
<img src="whatever.jpg">
</figure>而 CSS 看起来大概是这样,使用了嵌套选择器:
.zine {
...
&.horizontal {
...
}
&.vertical {
...
}
&:hover {
...
}
}我还没有做任何程序化的保障(比如 web components 或@scope)来确保组件之间不会互相干扰,但仅仅是有一个约定并尽力遵守,就已经感觉是很大的进步了。
接下来:用一些约定来保持整个站点的统一性,并让这些组件彼此协调!
3. 颜色
colours.css 里有一堆像这样的变量,我可以根据需要使用。颜色真的很难,在这次重构中我不想重新考虑颜色的使用,所以这部分保持原样。
我在这里试图执行的唯一规范是,网站中使用的所有颜色都要在这个文件中列出。
:root {
--pink: #fea0c2;
--pink-light: #F9B9B9;
--red: #f91a55;
--orange: rgb(222, 117, 31);
...
}4. 字体大小
我喜欢 Tailwind 的一点是,如果我想设置字体大小,我只需要想“嗯,我想要文字大一点”,写上 text-lg 就完事了!如果觉得还不够大,就改成 xl 或 2xl。不用去记到底是用 em 还是 px 还是 rem。
所以我定义了一堆变量,都是从 Tailwind 抄来的,像这样:
--size-xs: 0.75rem;
--line-height-xs: 1rem;
--size-sm: 0.875rem;
--line-height-sm: 1.25rem;然后如果我想设置字体大小,就可以这样做。虽然比 Tailwind 啰嗦了一点,但目前我还算满意。
h3 {
font-size: var(--size-lg);
line-height: var(--line-height-lg);
}5. 工具类
有一些东西比如按钮,会出现在许多不同的组件里。我把这些叫做“工具类”。
我从 Tailwind 复制了一些工具类(比如 .sr-only,用于只对屏幕阅读器用户可见的内容)。
这一部分很小,我会谨慎地在这里做改动。
6. 基础样式
“基础”样式是应用于整个站点的、我自己选择的样式。这一部分我必须保持得非常小,因为我还没有足够信心在全站范围内强制施加很多样式。目前我只对这两条比较有把握,而且 <section> 这一条我可能还会改:
/* put a 950px column in the middle of each <section> */
section {
--inner-width: 950px;
padding: 3rem max(1rem, (100% - var(--inner-width))/2);
}
a {
color: var(--orange);
}我觉得对于基础样式,对我来说最容易的方式是自下而上——先在基础样式里几乎什么都不放,然后在识别出想要的通用样式时,再把一些样式从组件中移到基础样式里。
7. 间距
对于如何管理内边距和外边距,我还没有完全想好方案。不过我现在肯定比以前用 Tailwind 时更有原则了——以前我就是随意地到处加内边距和外边距,直到看起来顺眼为止。
现在我正努力让外层布局组件尽可能负责间距。比如,如果我有一个 <section>,里面有一堆子元素,我希望它们之间有均匀的间距,就可能会这样做:
section > *+* {
margin-top: 1rem;
}一些启发我的博文:
8. 响应式设计:多用 grid!
我以前用 Tailwind 做响应式设计的方式是使用大量媒体查询。Tailwind 有这种 md:text-xl 语法,意思是“在 md 或更大尺寸下应用 text-xl 样式”。
现在我尝试了一种很不一样的做法,就是做出更灵活的 CSS grid 布局,不需要那么多断点。这很难,但学习 grid 能做到什么真的很有趣,而且这是我觉得用 Tailwind 做不到的一个好例子。
例如,我一直在学习如何使用 auto-fit 来自动在大屏幕上用 2 列、在小屏幕上用 1 列,像这样:
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content));
justify-content: center;我还大量使用了grid-template-areas,这是一个非常棒的功能,我觉得用 Tailwind 是用不了的。
一些灵感来源:
- A responsive grid layout with no media queries 来自 CSS Tricks
9. 构建系统:esbuild
在开发环境中,我不需要构建系统:CSS 现在已经内置了导入语句,像这样:
@import "reset.css";
@import "typography.css";
@import "colors.css";还有内置的嵌套选择器,像这样:
.page {
h2 { ...}
}如果需要,我可以用 esbuild 来为生产环境打包 CSS 文件。大概像这样。
esbuild style.css --bundle --loader:.svg=dataurl --loader:.woff2=file --outfile=/tmp/out.css虽然我通常会避免使用 CSS 和 JS 构建系统,但我不介意使用 esbuild(我在2021 年在这里写过),因为它基于 Web 标准,而且是一个静态的 Go 二进制文件。
为什么要迁离 Tailwind?
有几个人问我为什么要迁离 Tailwind。有几个促成因素:
- 自 2018 年以来,Tailwind 对构建系统的依赖越来越重,我觉得不用构建系统就几乎不可能使用新版本的 Tailwind。所以这些年来我一直在使用 Tailwind v2。(不过显然还有litewind)
- 一直以来 Tailwind 本来就应该配合构建系统使用,但我从来没那样做过,所以我的很多项目里都有 2.8MB 的
tailwind.min.css文件(gzip 后 270K),感觉有点傻。 - 我现在对 CSS 的掌握比刚开始用 Tailwind 时好多了
- 归根结底 Tailwind 是有限制的:如果你想在 CSS 里做些奇怪的事情,用 Tailwind 并不总是能实现。这些限制可能非常有用(这篇文章的很多内容就是在重新实现 Tailwind 的一些限制!)但现在我希望能有所取舍、自主选择。
- 我最后搞出了在同一个项目里混用原生 CSS 和 Tailwind 的网站,维护起来一点也不好玩
- 我开始好奇写更多语义化 HTML 会是什么感觉。
我感到好奇的 CSS 功能
在做这些的过程中,我了解到了很多我还没用过、但有朝一日想去了解的 CSS 功能:
@layer(来自A Whole Cascade of Layers)- @scope)(尤其是规范中这个关于如何在“组件”CSS 设计中使用 @scope 的例子!)
- container queries(容器查询)
- subgrid(子网格)
我迁离 Tailwind 的最后一个原因
在这篇文章里我谈了很多从使用 Tailwind 中学到的东西,这些都是真的。
但 3 年前我读过一篇叫做Tailwind and the Femininity of CSS 的文章,它让我印象深刻。说实话,我一开始对 CSS 的态度可能就有点像那篇文章所描述的那样:
他们听说它很简单,所以就以为它很容易。但当他们尝试使用它时,却行不通。那一定是这门语言的错,因为他们知道自己很聪明,而这本来应该是很容易的。
但在过去的 10 年里,我学会了真正热爱并尊重 CSS 这门技术。
所以多年前我就决定,对于“CSS 很难”这种说法,我要用更好地掌握 CSS、并认真对待它这门技术来回应,而不是贬低它。这样做彻底改变了我:我发现很多曾让我沮丧的问题(“居中是不可能的”)其实早在很久以前就已经在 CSS 中得到解决了,而且“居中”到底意味着什么并不总是那么直截了当,有多种实现方式也是合理的。CSS 之所以难,是因为它在解决一个难题!
在过去的 10 到 15 年里构建的新 CSS 功能(其中一些我在这篇文章中已经谈到!)让我印象深刻,它们让 CSS 更易于使用,而花时间提升自己的 CSS 技能是一次非常酷的体验。
而那篇文章让我觉得 Tailwind 助长了对 CSS 专业知识的轻视,而这不是我想参与的事情,即使 Tailwind 对我个人来说曾是一个有用的工具。尤其是在这个 LLM 时代,重视人类的专业知识比以往任何时候都更加重要。
另一篇影响了我的、批评 Tailwind 的博文:
暂时就到这里!
感谢Melody Starling(梅洛迪·斯塔林),她最初为wizardzines.com 设计并编写了 CSS,网站上所有酷炫有趣的东西都要归功于梅洛迪·斯塔林。
另外,我在做这个的过程中阅读了大量关于 CSS 的精彩博文(来自CSS Tricks、Smashing Magazine 等),我在本文中尝试链接了其中一些,非常感谢 CSS 社区中乐于分享实践的每一个人。
随机一篇博客