译:如何在 2024 年编写 CSS

原文:https://leerob.io/blog/css
作者:Lee Robinson
译者:ChatGPT 4 Turbo
校对:云谦

编者注:几个收获,1)虽然 2024 的 CSS 已经很强大,但编译步骤还是需要的,比如做语法降级、未使用样式裁剪等,2)流式 CSS 是个新概念,第一次听说,3)作者推荐了 CSS Modules、Tailwind CSS 和 StyleX 三种方案。

2024 年的 CSS 太棒了。

这篇帖子将是我关于 CSS 生态系统以及我目前使用的工具的笔记和想法的集合。

设计约束

用户体验

在访问网站时,加载样式表的极佳体验是什么样的?

  1. 样式表应尽可能快地加载(文件大小小)
  2. 样式表除非更改,否则不应重新下载(适当的缓存头)
  3. 页面内容应该很少布局偏移或没有
  4. 字体应尽可能快地加载,并最小化布局偏移

开发者体验

我们的工具必须帮助我们创造更好的用户体验。开发者体验虽然重要,但不能凌驾于用户体验之上。

我们使用的样式工具的 DX 如何帮助我们创造更好的 UX?

  1. 剪除未使用的样式,压缩并压缩 CSS 以减小文件大小
  2. 生成哈希文件名以实现安全、不可变的缓存²
  3. 将 CSS 文件打包在一起以减少网络请求
  4. 避免命名冲突以防止视觉回归(visual regressions)

如何帮助我们编写更易维护、更令人愉快的 CSS?

  1. 删除相应 UI 代码时容易删除样式
  2. 易于遵循设计系统或一系列主题
  3. 编辑器反馈支持 TypeScript,自动完成和代码检查
  4. 在编辑器中接收工具反馈以防止错误(类型检查,代码审查)

2024 年的 CSS

编写出色的样式从未如此简单,无需任何额外工具。

下面的例子使用了许多最新的跨浏览器支持的 CSS 功能,无需任何构建步骤。你可能不再需要 Sass 或 Less 了!

https://codesandbox.io/s/jyftfw?file=%2Fstyles.css&utm_medium=sandpack

这是否意味着工具不再必要了?对某些人来说,是的。

构建步骤

为了满足上述设计约束,你可能需要一个构建步骤。

不太可能所有用户都使用最新版本的浏览器。但更重要的是,总会有一些新的语法尚未得到跨浏览器的支持,而你会想要使用这些语法。

你可以手动编写 @supports 规则来检查浏览器支持,但这只能解决部分问题。与其让人类来优化 CSS,为什么不让机器来处理呢

编译

编译器使以下工作流程变得简单:

  1. 自动删除任何未使用的样式,将文件打包以减少网络请求,添加供应商前缀,并通过删除空白和注释来压缩输出
  2. 自动生成唯一文件名,允许框架设置像 immutable 这样的缓存头,向浏览器发出内容永不更改的信号
  3. 指定目标浏览器(browserslist)并通过语法降级来编译现代 CSS 功能,以便与这些浏览器兼容

流式 CSS

你访问 Google 来预订航班。它无法预先计算出你的意图,因此你最初得到的 UI 是一个搜索栏。你搜索 "Flight SFO to NYC" ,服务器会流式传输一个航班小部件以选择日期。

Google 不可能提前包含所有可能的小部件。货币转换、计时器、实时体育比分,应有尽有。这些小部件的 UI 和样式需要动态流式传输。

React(和 Next.js)现在支持带有流式 SSRCSS 的模式。在 React 模型中,你定义了作为组件的 UI,这些组件依赖于样式。我们如何能够安全地为小部件流式传输样式,而不影响页面上的任何内容?

样式需要是作用域限定的,或者是原子化的,这样即使它们比它们要设置样式的 DOM 内容更早加载,也不会改变页面上已有元素的样式。

例如,CSS Modules 有样式规则限定在导入它的组件范围内。Tailwind 使用原子化的工具类,这些类被编译成一个单独的样式表,在任何类被使用之前加载。StyleX 也生成原子类。全局样式与流式传输不太兼容,除非在流的开始就加载。

我的推荐

CSS Modules

CSS Modules 是在普通 CSS 基础上的一个小而有影响力的增强。

他们满足了我们想要的 UX 约束条件,以及大部分(但不是全部)的 DX 约束条件。它们在几乎所有现代打包工具和框架中都可用。你可以复制 / 粘贴现有的 CSS 选择器,它们将在 CSS 模块中无需任何更改即可工作。

它们无法生成原子样式。它们不支持使用多个主题(仅支持 CSS 变量)。而且因为样式代码不在你的 TypeScript 文件中,你无法获得类型安全和自动完成。但这些限制对你来说可能是可以接受的。

💡 Vite 使用支持 CSS Modules 的 Lightning CSS,不久后 TailwindNext.js 也将使用。像 postcssautoprefixer 这样的工具正在被更快的、一体化的 Rust 工具链所取代。

Tailwind CSS

Tailwind 使用编译器生成仅使用的类。因此,虽然实用程序 CSS 框架包含许多可能的类名,但只有使用的类(例如 "font-bold text-2xl" )会被包含在单个编译后的 CSS 文件中。

假设你只编写 Tailwind 代码,你的打包文件大小将不会超过所使用的 Tailwind 类的总和。你几乎不可能用到它们全部。这意味着生成的 CSS 文件大小有一个固定的上限,然后通过压缩、缩小和缓存来达到最佳性能。

你不必只编写 Tailwind 样式。Tailwind 类只是遵循设计系统的普通 CSS 工具类。例如,你可以将 Tailwind 与 CSS Modules 混合使用。

Tailwind 并非没有权衡。有一系列工具可以与之搭配:

Tailwind 最有争议的部分是它的语法。它既被喜爱也被讨厌。在我用它构建了一些东西之前,我并不欣赏 Tailwind,所以如果你的初步反应是反感的,我建议尝试一下。

https://codesandbox.io/s/z7gkmc?file=%2Findex.html&utm_medium=sandpack

StyleX

大多数 CSS-in-JS 库存在两个问题:

  1. 性能: 组件必须将 JS 中编写的样式转换为 CSS,并在渲染时插入到文档中。这可能会带来相当大的成本,这就是为什么正在向像 StyleX 这样的“零运行时”库转移的原因。
  2. 兼容性: 许多现有的 CSS-in-JS 库已经增加了对 React 流式服务器渲染的支持,但仍然不兼容其他性能优化,比如将应用程序的部分内容移至 React 服务器组件

为了解决这些问题,已经创建了像 Vanilla ExtractPanda 等“零运行时”CSS-in-JS 库。

StyleX 是最新的 CSS-in-JS 库,它解决了这些问题以及更多。如果你想深入了解,我建议阅读“Thinking in StyleX”。

这个例子是我第一次使用 StyleX。虽然它对开源来说还很新(生态系统也反映了这一点),但它并不是一个新库。它支持所有 Meta 网站:Facebook、Instagram、WhatsApp 和 Threads。

你仍然需要给事物命名 🫠 输入 buttonWrapperContainer

结论

CSS 对我来说现在有趣吗?我想是的。我很期待未来几年会带来什么。

你会选择不同的东西吗?我漏掉了什么吗?请告诉我。


¹: More: linear() easing, subgrid, dynamic viewport units, color spaces, and @layer.

²:由于文件名保证是唯一的,你可以设置 immutable 缓存头,告诉浏览器内容永远不会改变。这允许浏览器永久缓存文件,这对性能来说是非常好的。