Tailwind CSS 4 在 Astro 里的配置
- Date / 日期
- Updated / 更新
- 2026.10.12
- Reading / 阅读
- 6 Min
- Words / 字数
- 1199
- Tags / 标签
- #Astro#Tailwind CSS#前端#样式
Tailwind CSS 4 在 Astro 里的配置
这篇和之前那篇的关系
博客最早用的是 Tailwind 3,配置写在 tailwind.config.js 里,通过 @astrojs/tailwind 集成挂上去,那套流程记在《Astro 框架中配置与使用 Tailwind CSS》。
后来重构时换成了 Tailwind 4。它最大的变化是配置搬回了 CSS:没有 tailwind.config.js,也不需要再往 content 数组里列模板路径。下面记的是现在实际在用的方式。
装配:一个 Vite 插件加一行 import
依赖只有两个:
pnpm add tailwindcss @tailwindcss/vitetailwindcss 是核心,@tailwindcss/vite 是给 Vite 用的插件。Astro 的底层是 Vite,所以直接挂在 vite.plugins 里就行,不再需要 integrations:
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({ vite: { plugins: [tailwindcss()], },})然后在样式入口的第一行把 Tailwind 整个引入:
@import 'tailwindcss';就这些。没有配置文件,也没有 content 数组,v4 自己扫描项目里的源文件来收集用到的类,v3 时代那个”忘了把某类文件加进 content,结果样式被 purge 掉”的问题不存在了。
dark: 跟着 data-theme 走
v4 默认的 dark: 变体看的是系统的 prefers-color-scheme。而本站的明暗是手动切换的,状态写在 <html data-theme="light|dark"> 上,跟系统偏好无关。
v3 时代这件事靠 darkMode: 'class' 加上往根元素塞一个 dark 类。v4 换成了在 CSS 里重定义变体:
/* 让 dark: 变体跟随 data-theme 属性,而不是系统偏好 */@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));这行的意思是:命中 dark: 的工具类,选择器改写成”元素自己或它的祖先带 data-theme="dark"”。
外面包的那层 :where() 不是装饰。:where() 的特异性是 0,不加它的话这个变体会给选择器加上 [data-theme="dark"] 那部分权重,一些本该被后面工具类覆盖的规则就盖不动了。Tailwind 官方给的写法也是这样。
@theme:把已有的 CSS 变量接成工具类
站点本来就有一套颜色变量,明暗两套值分别在 :root 和暗色选择器下定义:
:root { --c-page: #eae5e1; --c-ink: #2a2724; --c-accent: #9b7247; /* … */}要在组件里用 Tailwind 的写法调这些颜色,就得把它们注册成主题变量。v4 用 @theme 做这件事:
@theme inline { --color-page: var(--c-page); --color-surface: var(--c-surface); --color-code: var(--c-code); --color-ink: var(--c-ink); --color-muted: var(--c-muted); --color-line: var(--c-line); --color-accent: var(--c-accent);}注册之后就有 bg-page、text-ink、text-muted、border-line、text-accent 这些工具类了。
这里的关键是 inline。不加它,Tailwind 会把变量的值算出来写进生成的类里;加了 inline,生成的是 var(--c-ink) 这样的引用。差别在切主题的时候:站点换肤是改 <html> 上的变量值,只有引用形式才会跟着变。写死了的话,切到暗色下工具类的颜色还是原来那套。
字体栈也放在 @theme 里,不过不需要 inline,因为字体名本身就是字面量:
@theme { --font-sans: 'MiSans', 'PingFang SC', /* … */ sans-serif; --font-mono: 'JetBrainsMono Nerd Font', /* … */ monospace; --font-serif: 'Times New Roman', Times, /* … */ serif;}定义完就有 font-sans、font-mono、font-serif 可用。其中 --font-serif 的栈是”西文衬线 + 中文无衬线”,因为中文衬线字体在这块屏幕上不好看,但英文用 Times New Roman 更合适。
一个坑:自己写的组件样式必须放进 @layer components
站点里有一批自己的排版类,比如 .rl-label。它们必须包在层里:
@layer components { .rl-label { font-size: 0.6875rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--c-muted); }}这跟 CSS 的层叠层有关。Tailwind v4 的工具类都放在 utilities 层里,而 CSS 里没有层级的规则永远压过任何层,这跟书写顺序无关。所以不包层的话,.rl-label 里那句 color 会把元素上写的 hover:text-accent 直接吃掉,而且看代码完全看不出问题。
实际用起来是什么样
组件和页面里就直接写类名:
<div class="rounded-sm border border-line bg-surface p-4"> <span class="rl-label">DATE / 日期</span> <p class="mt-2 text-sm text-muted">2026-10-12</p></div>配合 @theme inline 注册的那批颜色,text-muted 在明暗两套主题下会各自取到对应的值,不需要写 dark: 分支。真正需要分主题调的地方才用 dark:,比如:
<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-white">主题自适应</div>从 v3 迁过来要改的几处
| v3 的写法 | v4 的写法 |
|---|---|
tailwind.config.js 里的 theme.extend | CSS 里的 @theme { } |
content: ['./src/**/*.{html,js}'] | 不需要,自动检测源文件 |
darkMode: 'class' | @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *)) |
plugins: [require('@tailwindcss/typography')] | @plugin '@tailwindcss/typography'; |
@tailwind base; @tailwind components; @tailwind utilities; | @import 'tailwindcss'; |
@astrojs/tailwind 集成 | @tailwindcss/vite 插件 |
自定义工具类从 @layer utilities 里的普通规则改成了 @utility 指令,不过本站还没用到,暂时没验证过写法。
一点体会
配置搬到 CSS 之后最舒服的地方是改样式和改配置在同一个文件里。以前调一个主题色要在 tailwind.config.js 和 global.css 之间来回跳,现在是挨着的两段;而且 @theme inline 让 Tailwind 的工具类和站点原有的 CSS 变量合成了一套,不用再维护两份颜色定义。

Comment评论