告别Tailwind,学习组织CSS

Lobsters Hottest 工具

摘要

作者反思了从Tailwind CSS迁移到带语义HTML的原生CSS的过程,分享了利用从Tailwind学到的重置、组件和工具类等系统来组织CSS的心得。

<p><a href="https://lobste.rs/s/7a6atx/moving_away_from_tailwind_learning">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/05/15 19:03

# 告别 Tailwind,学习结构化 CSS 来源:https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/ 你好!8 年前,我曾兴奋地写下发现 Tailwind 的体验(https://jvns.ca/blog/2018/11/01/tailwind--write-css-without-the-css/)。那时我真的不知道如何结构化 CSS 代码,面对一堆混乱不堪的代码和 Tailwind 之间的选择,我非常乐意选择 Tailwind。它帮我制作了许多小型网站! 过去一周左右,我把几个网站从 Tailwind 迁移到了更语义化的 HTML + 原生 CSS,这个过程超有趣、超有收获,以下是我学到的一些东西!和往常一样,我不是全职前端开发者,所以我的 CSS 学习多年来一直是断断续续的。 ### 结果发现 Tailwind 教会了我很多(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#it-turns-out-tailwind-taught-me-a-lot) 当我开始思考如何结构化 CSS 时,起初我觉得很畏惧:我不太擅长组织 CSS!但后来我阅读了一些关于如何结构化 CSS 的博客文章(比如《层叠层级的整体》(https://www.miriamsuzanne.com/2022/09/06/layers/)或《2024 年我如何写 CSS》(https://jacobb.nyc/writing/how-i-write-css-in-2024)),我意识到几件事: 1. 每个 CSS 代码库都包含许多不同的事情(布局!字体!颜色!通用组件!) 2. 拥有系统或准则来管理这些事项非常有用,否则事情会陷入混乱 3. Tailwind 对其中某些事项有着自己的系统,而我已经熟悉了这些系统!也许我可以模仿我喜欢的系统! 例如,Tailwind 拥有: - 一个重置样式表 - 一个色彩调色板(https://jvns.ca/blog/2026/05/04/css-colour-palettes/) - 一个字体比例尺(https://v2.tailwindcss.com/docs/font-size) ### 我打算讨论的系统(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#the-systems-i-m-going-to-talk-about) 我打算讨论 CSS 代码库的几个方面,以及目前我对每个方面希望施加何种规则的想法。其中一些是从 Tailwind 复制来的,一些不是。 1. 重置 2. 组件 3. 颜色 4. 字体大小 5. 工具类 6. 基础样式 7. 间距 8. 响应式设计 9. 构建系统 ### 1. 重置(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#1-reset) 我直接复制了 Tailwind 的“preflight 样式”(https://v2.tailwindcss.com/docs/preflight),通过进入 `tailwind.css` 复制了前 200 行左右。我注意到,随着时间的推移,我与 Tailwind 的 CSS 重置建立了一种关系,例如 Tailwind 为每个元素设置了 `box-sizing: border-box`(这意味着元素的宽度包含其内边距): ``` * { box-sizing: border-box; } ``` 我觉得如果脱离这些重置来写 CSS,对我来说会是一个相当大的调整。而且我相信 Tailwind 重置中还有许多其他东西(比如 `html { line-height: 1.5; }`)是我下意识已经习惯的,甚至都没有意识到它们的存在。 ### 2. 组件(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#2-components) 接下来是 CSS 的主体部分!这里的思路是按照“组件”来组织 CSS,这种方式在精神上与 Vue 或 React 组件相关(尽管网站上可能根本没有 JavaScript)。基本思路是: 1. 每个“组件”拥有一个唯一的类 2. 一个组件的 CSS 决不会覆盖其他任何组件的 CSS 3. 每个组件拥有自己的 CSS 文件 这样,编辑一个组件的 CSS 就不会意外破坏另一个组件中的内容。而且可能 80% 我想要更改的 CSS 都分布在各个组件文件中,所以如果我编辑一个 100 行的组件,我只需考虑那 100 行代码。思考起来容易得多。 例如,这个 HTML 可能是 `.zine` “组件”: ``` <div class="zine"> ... </div> ``` CSS 看起来像这样,使用了嵌套选择器: ```css .zine { ... &.horizontal { ... } &.vertical { ... } &:hover { ... } } ``` 我没有做任何编程性的措施(比如 web components 或 @scope(https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@scope))来确保组件之间不会相互干扰,但仅仅有一个约定并尽量遵守,已经感觉是很大的进步了。 接下来:一些约定,用以在网站中保持一致性,并使这些组件相互协调! ### 3. 颜色(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#3-colours) `colours.css` 中有许多像这样的变量,我可以按需使用。颜色真的很难处理,我不想在这次重构中重新审视颜色的使用,所以我保持了原样。我试图强制执行的唯一准则是:网站上使用的所有颜色都列在这个文件中。 ```css :root { --pink: #fea0c2; --pink-light: #F9B9B9; --red: #f91a55; --orange: rgb(222, 117, 31); ... } ``` ### 4. 字体大小(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#4-font-sizes) Tailwind 让我欣赏的一点是,如果我想设置字体大小,我只需想“嗯,我想要文字大一点”,然后写 `text-lg` 就行了!如果不够大,就用 `xl` 或 `2xl`。不用费心去记是用 `em`、`px` 还是 `rem`。 所以我定义了一组从 Tailwind 借鉴来的变量,像这样: ```css --size-xs: 0.75rem; --line-height-xs: 1rem; --size-sm: 0.875rem; --line-height-sm: 1.25rem; ``` 然后如果想设置字体大小,可以这样写。比 Tailwind 稍微冗长一些,但目前我很满意。 ```css h3 { font-size: var(--size-lg); line-weight: var(--line-weight-lg); } ``` ### 5. 工具类(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#5-utilities) 有一些东西,比如按钮,会在许多不同组件中出现。我把它们称为“工具类”。我从 Tailwind 复制了一些工具类(比如用于只应该出现在屏幕阅读器用户面前的 `.sr-only`)。这个部分很小,我会小心谨慎地进行更改。 ### 6. 基础样式(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#6-the-base) “基础”样式是那些覆盖整个网站、由我自己选择的样式。我必须把这个部分保持得非常小,因为我没有足够的信心去强制对整个网站应用大量样式。目前我觉得可以接受的只有这两条,而且将来可能会改变 `a` 的那条: ```css /* 在中间放置一个 950px 的列 */ section { --inner-width: 950px; padding: 3rem max(1rem, (100% - var(--inner-width))/2); } a { color: var(--orange); } ``` 我认为对于基础样式,最适合我的是自下而上的方式——首先基础样式里几乎什么都不放,然后当我发现普遍想要的公共样式时,再逐渐把一些样式从组件移到基础样式中。 ### 7. 间距(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#7-spacing) 我还没有完全想好管理内边距和外边距的方法。不过,我绝对在尝试比使用 Tailwind 时更有原则,那时我只会随意地在各处添加 padding 和 margin,直到看起来满意为止。 现在我正努力让外层的布局组件尽可能负责间距。例如,如果我有一个 `<section>` 包含许多子元素,并且我希望它们之间有空隙,我可以用这个来均匀地分隔子元素: ```css section > *+* { margin-top: 1rem; } ``` 一些启发性的博文: - 猫头鹰选择器(https://piccalil.li/blog/my-favourite-3-lines-of-css/) - “无外边距”(https://kyleshevlin.com/no-outer-margin/) ### 8. 响应式设计:多用 grid!(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#8-responsive-design-use-more-grid) 我在 Tailwind 中做响应式设计的方式是大量使用媒体查询。Tailwind 有 `md:text-xl` 这样的语法,意思是“在 `md` 或更大尺寸下应用 `text-xl` 样式”。现在我尝试了一种截然不同的方法:创建更灵活的 CSS grid 布局,不需要那么多断点。这很难,但学习 grid 能做什么非常有趣,而且这是一个我认为 Tailwind 做不到的好例子。 例如,我学习了如何使用 `auto-fit` 自动在大屏幕上使用 2 列,在小屏幕上使用 1 列,像这样: ```css display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content)); justify-content: center; ``` 我还大量使用了 `grid-template-areas`(https://wizardzines.com/comics/css-grid-areas/),这是一个很棒的 feature,我认为 Tailwind 无法实现。 一些启发: - 无需媒体查询的响应式网格布局(https://css-tricks.com/a-responsive-grid-layout-with-no-media-queries/),来自 CSS Tricks ### 9. 构建系统:esbuild(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#9-the-build-system-esbuild) 在开发中,我不需要构建系统:CSS 现在既有内置的 `@import` 语句,像这样: ```css @import "reset.css"; @import "typography.css"; @import "colors.css"; ``` 也有内置的嵌套选择器,像这样: ```css .page { h2 { ...} } ``` 如果需要,我可以用 `esbuild` 为生产环境打包 CSS 文件。看起来像这样: ``` esbuild style.css --bundle --loader:.svg=dataurl --loader:.woff2=file --outfile=/tmp/out.css ``` 尽管我通常避免使用 CSS 和 JS 构建系统,但我并不介意使用 esbuild(我曾在 2021 年写过关于它的文章(https://jvns.ca/blog/2021/11/15/esbuild-vue/)),因为它基于 Web 标准,而且是一个静态的 Go 二进制文件。 ### 为什么要从 Tailwind 迁移?(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#why-migrate-away-from-tailwind) 有几个人问我为什么从 Tailwind 迁移。一些促成因素包括: - 自 2018 年以来,Tailwind 变得更加依赖构建系统,我认为不使用构建系统就无法使用较新版本的 Tailwind。所以多年来我一直使用 Tailwind v2。(似乎还有 litewind(https://litewindcss.com/)) - 一直以来的规定是你应该配合构建系统使用 Tailwind,但我从来没有真正这样做过,所以我的许多项目中都有 2.8MB 的 `tailwind.min.css` 文件,感觉有点傻。 - 比起开始使用 Tailwind 时,我的 CSS 水平提高了很多 - 最终 Tailwind 是有限制的:如果你想在 CSS 中做“奇怪的事情”,用 Tailwind 并不总是可能的。这些限制可能非常有用(这篇帖子很多内容就是关于我重新实现 Tailwind 的一些限制),但到了现在这个阶段,我希望能够自己选择。 - 最终我会有一些混合使用原生 CSS 和 Tailwind 的网站,维护起来并不愉快 - 我对编写更语义化的 HTML 会是什么感觉感到好奇 ### 我感兴趣的一些 CSS 特性(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#css-features-i-m-curious-about) 在这个过程中我了解到了很多没有使用过但将来某天想学习的 CSS 特性: - `@layer`(来自《层叠层级的整体》(https://www.miriamsuzanne.com/2022/09/06/layers/)) - @scope(https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@scope) - container queries(https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Containment/Container_queries) - subgrid(https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout/Subgrid) ### 暂时就这些!(https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/#that-s-all-for-now) 我仍然很高兴自己当初开始使用 Tailwind,即使现在正在离开它。我从使用它中学到了很多,即使在删除 `tailwind.min.css` 之后,我仍然可以在网站上使用其中的一些部分。 感谢 Melody Starling(https://melody.dev/),她最初设计并编写了 wizardzines.com(https://wizardzines.com/) 的 CSS,网站上所有酷炫有趣的东西都归功于 Melody。另外,我在做这个项目的过程中阅读了大量关于 CSS 的精彩博文(来自 CSS Tricks(https://css-tricks.com/)、Smashing Magazine(https://www.smashingmagazine.com/)等),我在这篇文章中尽量链接了一些,非常感谢 CSS 社区分享其实践的热情。

相似文章

现代前端复杂性:本质的还是偶然的?

Lobsters Hottest

本文分析了现代前端开发为何日趋复杂,回顾了从静态 HTML 文档、AJAX 到基于 React、Vue、Angular 和 Svelte 等框架的单页应用(SPA)的演进历程,并探讨这种复杂性属于本质复杂度还是偶然复杂度。

Tailgrids 3.0

Product Hunt

Tailgrids 3.0 是一个专为 Tailwind CSS 和 AI 工作流设计的开源 React UI 库。

使用 CSS 为文本、图像和表格实现垂直节奏

Lobsters Hottest

本文探讨了在网页设计中使用 CSS 实现垂直节奏,特别是利用 `rlh` 单位进行文本对齐,并提供了一种 JavaScript 变通方案,以便响应式图像保持一致的间距。

就他妈用 React

Lobsters Hottest

这篇主观性很强的文章激进地主张在复杂 Web 应用中使用现代 JavaScript 框架(如 React)而非纯 HTML,认为复杂性需要合适的工具。