Moving away from Tailwind, and learning to structure my CSS

Moving away from Tailwind, and learning to structure my CSS

告别 Tailwind,学习如何构建我的 CSS

Hello! 8 years ago, I wrote excitedly about discovering Tailwind. At that time I really had no idea how to structure my CSS code and given the choice between a pile of complete chaos and Tailwind, I was really happy to choose Tailwind. It helped me make a lot of tiny sites! 你好!8 年前,我曾兴奋地写下自己发现 Tailwind 的经历。那时我真的不知道该如何组织 CSS 代码,在“一团乱麻”和“Tailwind”之间,我非常庆幸自己选择了 Tailwind。它帮助我制作了许多小型网站!

I spent the last week or so migrating a couple of sites away from Tailwind and towards more semantic HTML + vanilla CSS, and it was SO fun and SO interesting, so here are some things I learned! As usual I’m not a full-time frontend developer and so all of my CSS learning has happened in fits and starts over many years. 过去一周左右,我花时间将几个网站从 Tailwind 迁移到了更具语义化的 HTML + 原生 CSS。这个过程非常有趣,也让我学到了很多东西!像往常一样,我并非全职前端开发人员,因此我所有的 CSS 知识都是多年来断断续续积累的。

It turns out Tailwind taught me a lot. When I started thinking about structuring CSS, I was intimidated at first: I’m not very good at structuring my CSS! But then I started reading blog posts talking about how to structure CSS (like A whole cascade of layers or How I write CSS in 2024) and I realized a couple of things: 事实证明,Tailwind 教会了我很多。当我开始思考如何构建 CSS 时,起初感到很畏惧:我不擅长组织 CSS!但后来我开始阅读一些关于 CSS 架构的博客文章(例如《A whole cascade of layers》或《How I write CSS in 2024》),我意识到了几点:

  • Every CSS code base has a bunch of different things going on (layouts! fonts! colours! common components!)
  • It’s extremely useful to have systems or guidelines to manage each of those things, otherwise things descend into chaos.
  • Tailwind has systems for some of these, and I already know those systems! Maybe I can imitate the systems I like!
  • 每个 CSS 代码库中都有许多不同的元素(布局、字体、颜色、通用组件等)。
  • 拥有一套系统或准则来管理这些元素非常有用,否则一切都会陷入混乱。
  • Tailwind 为其中一些元素提供了系统,而我已经熟悉这些系统了!也许我可以模仿我喜欢的那些系统!

For example, Tailwind has: a reset stylesheet, a colour palette, a font scale. 例如,Tailwind 拥有:重置样式表、调色板、字体缩放比例。

The systems I’m going to talk about

我将要讨论的系统

I’m going to talk about a few aspects of my CSS codebase and my thoughts so far—what kind of rules I want to impose on the codebase for each one. Some of them are copied from Tailwind and some aren’t. 我将讨论我的 CSS 代码库的几个方面以及我目前的想法——即我想为每一部分设定什么样的规则。其中一些是从 Tailwind 借鉴的,另一些则不是。

  1. reset

  2. components

  3. colours

  4. font sizes

  5. utility classes

  6. the base

  7. spacing

  8. responsive design

  9. the build system

  10. 重置 (reset)

  11. 组件 (components)

  12. 颜色 (colours)

  13. 字体大小 (font sizes)

  14. 工具类 (utility classes)

  15. 基础样式 (the base)

  16. 间距 (spacing)

  17. 响应式设计 (responsive design)

  18. 构建系统 (the build system)


1. reset

I just copied Tailwind’s “preflight styles” by going into tailwind.css and copying the first 200 lines or so. I noticed that I’ve developed a relationship with Tailwind’s CSS reset over time, for example Tailwind sets box-sizing: border-box on every element (which means that an element’s width includes its padding):

1. 重置 (reset)

我直接复制了 Tailwind 的“preflight styles”,方法是进入 tailwind.css 并复制了前 200 行左右的代码。我注意到随着时间的推移,我已经习惯了 Tailwind 的 CSS 重置方式。例如,Tailwind 会为每个元素设置 box-sizing: border-box(这意味着元素的宽度包含其内边距):

* { box-sizing: border-box; }

I think it would be a real adjustment for me to switch to writing CSS without these, and I’m sure there are lots of other things in the Tailwind reset (like html {line-height: 1.5;}) that I’m subconsciously used to and don’t even realize are there. 我想,如果切换到没有这些重置样式的 CSS 环境,对我来说将是一个巨大的调整。我相信 Tailwind 的重置样式中还有很多其他内容(比如 html {line-height: 1.5;}),我已经潜意识地习惯了它们,甚至都没意识到它们的存在。


2. components

This next part is the bulk of the CSS! The idea here is to organize CSS by “components”, in a way that’s spiritually related to Vue or React components (though there might not actually be any Javascript at all in the site).

2. 组件 (components)

接下来的部分是 CSS 的主体!这里的核心思想是按“组件”组织 CSS,这在精神上与 Vue 或 React 组件相关(尽管网站中可能根本没有任何 JavaScript)。

Basically the idea is that:

  • Each “component” has a unique class.
  • The CSS for one component never overrides the CSS for any other component.
  • Each component has its own CSS file. 基本思路是:
  • 每个“组件”都有一个唯一的类名。
  • 一个组件的 CSS 绝不会覆盖另一个组件的 CSS。
  • 每个组件都有自己的 CSS 文件。

So editing the CSS for one component won’t mysteriously break something in another component. And probably like 80% of the CSS that I would actually want to change is in various component files, so if I’m editing a 100-line component, I just have to think about those 100 lines. It’s way easier for me to think about. 这样,编辑一个组件的 CSS 就不会莫名其妙地破坏另一个组件。而且,我真正想要修改的 CSS 中大约 80% 都在各个组件文件中,所以如果我正在编辑一个 100 行的组件,我只需要考虑这 100 行代码。这对我来说思考起来容易多了。

For example, this HTML might be the .zine “component”: 例如,这段 HTML 可能就是 .zine “组件”:

<figure class="zine horizontal">
  <img src="whatever.jpg">
</figure>

And the CSS looks something like this, using nested selectors: 而 CSS 看起来像这样,使用了嵌套选择器:

.zine {
  ...
  &.horizontal { ... }
  &.vertical { ... }
  &:hover { ... }
}

I haven’t done anything programmatic (like web components or @scope) that ensures that components won’t interfere with each other, but just having a convention and trying my best already feels like a big improvement. 我还没有做任何程序化的处理(如 Web Components 或 @scope)来确保组件之间互不干扰,但仅仅是建立一种约定并尽力去遵守,就已经让我感觉有了很大的进步。


3. colours

colours.css has a bunch of variables like this which I can use as necessary. Colour is really hard and I didn’t want to revisit my use of colour in this refactor, so I left this alone. The only guideline I’m trying to enforce here is that all colours used in the site are listed in this file.

3. 颜色 (colours)

colours.css 包含了一堆像这样的变量,我可以根据需要使用它们。配色真的很难,我不想在这次重构中重新考虑配色方案,所以我保持原样。我在这里试图强制执行的唯一准则就是:网站中使用的所有颜色都必须列在这个文件中。

:root {
  --pink: #fea0c2;
  --pink-light: #F9B9B9;
  --red: #f91a55;
  --orange: rgb(222, 117, 31);
  ...
}

4. font sizes

One thing I appreciated about Tailwind was that if I wanted to set a font size, I could just think “hm, I want the text to be big”, write text-lg, and be done with it! And maybe if it’s not big enough I’d use xl or 2xl instead. No trying to remember whether I’m using em or px or rem.

4. 字体大小 (font sizes)

我欣赏 Tailwind 的一点是,如果我想设置字体大小,我只需要想“嗯,我想要大一点的文字”,写上 text-lg 就搞定了!如果不够大,我还可以用 xl2xl。不需要去纠结我到底是在用 empx 还是 rem

So I defined a bunch of variables, taken from Tailwind, like this: 所以我定义了一堆变量,借鉴了 Tailwind 的做法,如下所示:

--size-xs: 0.75rem;
--line-height-xs: 1rem;
--size-sm: 0.875rem;
--line-height-sm: 1.25rem;

Then if I want to set a font size, I can do it like this. It’s a little more verbose than Tailwind but I’m happy with it for now. 然后,如果我想设置字体大小,我可以这样做。虽然比 Tailwind 稍微冗长一点,但我目前很满意。

h3 {
  font-size: var(--size-lg);
  line-height: var(--line-height-lg);
}

5. utilities

There are some things like buttons that appear in many different components. I’m calling these “utilities”. I copied some utility classes from Tailwind (like .sr-only for things that should only appear for screenreader users). This section is pretty small and I try to be careful about making changes here.

5. 工具类 (utilities)

有些东西(比如按钮)会出现在许多不同的组件中。我称这些为“工具类”。我从 Tailwind 复制了一些工具类(比如用于屏幕阅读器可见内容的 .sr-only)。这部分内容很小,我在进行修改时会非常谨慎。


6. the base

“base” styles are styles that apply across the whole site that I chose myself. I have to keep this section really small because I’m not confident enough to enforce a lot of styles across the whole site. These are the only two I feel okay about right now, and I might change the <section> one:

6. 基础样式 (the base)

“基础”样式是指我为整个网站选择的通用样式。我必须保持这部分非常精简,因为我还没有足够的信心在全站强制执行大量样式。目前我只对这两项感到满意,而且我可能还会修改 <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);
}

I think for the base styles it’s going to be easiest for me to work kind of bottom up – first start with almost nothing in the base styles, and then move some styles from the components into base styles as I identify common things I want. 我认为对于基础样式,自下而上的工作方式最简单——先从几乎空白的基础样式开始,然后随着我发现一些通用的需求,再将组件中的某些样式迁移到基础样式中。


7. spacing

I haven’t completely worked out an approach to managing padding and margins yet. I’m definitely trying to be more principled than how I was doing it in Tailwind though, where I would just haphazardly put padding and margins everywhere until it looked the way I wanted. Right now I’m working…

7. 间距 (spacing)

我还没有完全想好管理内边距和外边距的方法。但我肯定会尝试比在 Tailwind 中更有原则——在 Tailwind 里,我只是随意地到处添加内边距和外边距,直到它看起来符合我的要求为止。目前我正在研究……