Published on

将 Tailwind CSS 项目从 v3 升级到 v4

Authors
  • Name
    Azimuth Ti
    Twitter

Tailwind CSS v4.0 专为 Safari 16.4+、Chrome 111+ 和 Firefox 128+ 设计。 如果需要支持较旧的浏览器,应坚持使用 v3.4,直到您的浏览器支持要求发生变化,再升级。

Tailwind CSS v4.0 是该框架的新主要版本,项目没有进行重大更改,仅有一些必要更新。这里介绍将项目从 v3 升级到 v4 所需的所有步骤。

使用升级工具

如果您想将项目从 v3 升级到 v4,可以使用官方的的升级工具来完成绝大多数繁重的工作:

$ npx @tailwindcss/upgrade

对于大多数项目,升级工具将自动执行整个迁移过程,包括更新依赖项、将配置文件迁移到 CSS 以及处理对模板文件的任何更改。

升级工具需要 Node.js 20 或更高版本,因此请确保在运行之前更新的环境。

官方建议在新分支中运行升级工具,然后仔细查看差异并在浏览器中测试您的项目,以确保所有更改看起来都正确无误。在复杂的项目中,您可能需要手动调整一些内容,但无论哪种方式,该工具都会为您节省大量时间。

手动升级

使用PostCSS

在 v3 中,tailwindcss包是一个 PostCSS 插件,但在 v4 中,PostCSS 插件位于专用的@tailwindcss/postcss包中。

此外,在 v4 中,导入和供应商前缀现在会自动为你处理,因此可以删除 postcss-import 和 autoprefixer(如果它们在你的项目中)

// postcss.config.mjs
export default {
  plugins: {
-   'postcss-import': {},
-   tailwindcss: {},
-   autoprefixer: {},
+   '@tailwindcss/postcss': {},
  },
}

使用Vite

如果你正在使用 Vite,建议从 PostCSS 插件迁移到我们新的专用 Vite 插件,以提高性能和最佳的开发人员体验:

// vite.config.ts
import { defineConfig } from 'vite'
+ import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
+    tailwindcss(),
  ],
})

使用Tailwind CLI

在 v4 中,Tailwind CLI 位于专用的 @tailwindcss/cli 包中。更新构建命令以改用新包:

#Terminal
- npx tailwindcss -i input.css -o output.css
+ npx @tailwindcss/cli -i input.css -o output.css

v4中的所有重大更改

升级工具将自动处理大部分这些更改,因此强烈建议使用升级工具升级项目。

浏览器要求

Tailwind CSS v4.0 专为现代浏览器设计,面向 Safari 16.4、Chrome 111 和 Firefox 128。我们依赖现代 CSS 功能,如 @propertycolor-mix() 来提供核心框架功能,而 Tailwind CSS v4.0 将无法在较旧的浏览器中运行。

如果需要支持较旧的浏览器,建议暂时坚持使用 v3.4。官方正在积极探索一种兼容模式,以帮助人们尽早升级。

删除@tailwind 指令

在 v4 中,使用常规 CSS @import 语句导入 Tailwind,而不是使用在 v3 中使用的 @tailwind 指令:

- @tailwind base;
- @tailwind components;
- @tailwind utilities;

+ @import 'tailwindcss';

删除已经弃用的程序属性

删除了 v3 中已弃用且多年来未记录的所有程序属性。以下是已删除的内容以及现代替代方案的列表:

DeprecatedReplacement
bg-opacity-*Use 使用不透明度修饰符,如bg-black/50
text-opacity-*使用不透明度修饰符,如 text-black/50
border-opacity-*使用不透明度修饰符,如 border-black/50
divide-opacity-*使用不透明度修饰符,如 divide-black/50
ring-opacity-*使用不透明度修饰符,如 ring-black/50
placeholder-opacity-*使用不透明度修饰符,如 placeholder-black/50
flex-shrink-*shrink-*
flex-grow-*grow-*
overflow-ellipsistext-ellipsis
decoration-slicebox-decoration-slice
decoration-clonebox-decoration-clone

重命名的程序属性

v4 中重命名了以下程序属性,以使其更加一致和可预测:

v3v4
shadow-smshadow-xs
shadowshadow-sm
drop-shadow-smdrop-shadow-xs
drop-shadowdrop-shadow-sm
blur-smblur-xs
blurblur-sm
backdrop-blur-smbackdrop-blur-xs
backdrop-blurbackdrop-blur-sm
rounded-smrounded-xs
roundedrounded-sm
outline-noneoutline-hidden
ringring-3

更新了shadow、radius、blur scales

官方重命名了默认的shadow、radius、blur scales,以确保每个工具都有一个命名值。“bare”版本仍然适用于向后兼容性,但<utility>-sm程序属性看起来会有所不同,除非更新到它们各自的<utility>-xs版本。

要针对这些更改更新项目,请将所有 v3 程序属性替换为其 v4 版本:

- <input class="shadow-sm" />
+ <input class="shadow-xs" />

- <input class="shadow" />
+ <input class="shadow-sm" />

重命名的outline程序属性

现在,outline程序属性默认将outline-width: 1px设置为与 border 和 ring 程序属性更加一致。此外,所有outline-<number>程序属性都将outline-style默认为solid,无需将它们与outline组合在一起:

-<input class="outline outline-2" />
+<input class="outline-2" />

outline-none程序属性以前实际上并未设置outline-style: none,而是设置了一个不可见的轮廓,出于可访问性原因,该轮廓仍将以强制颜色模式显示。

为了更清楚地说明这一点,我们已将此程序属性重命名为outline-hidden,并添加了一个新的outline-none程序属性,它实际上设置了outline-style: none

要针对此更改更新您的项目,请将outline-none的任何用法替换为outline-hidden

-<input class="focus:outline-none" />
+<input class="focus:outline-hidden" />

Default ring width change

在 v3 中,ring程序属性添加了一个3px的环。我们在 v4 中将其更改为1px,以使其与边框和轮廓保持一致。

要针对此更改更新您的项目,请将ring的任何用法替换为ring-3

-<input class="ring ring-blue-500" />
+<input class="ring-3 ring-blue-500" />

Space-between selector 间距选择器

我们更改了 space-x-* space-y-* 程序属性使用的选择器,以解决大页面上的严重性能问题:

/* Before */
.space-y-4 > :not([hidden]) ~ :not([hidden]) {
  margin-top: 1rem;
}
/* Now */
.space-y-4 > :not(:last-child) {
  margin-bottom: 1rem;
}

如果您曾经将这些程序属性与内联元素一起使用,或者如果您向子元素添加其他边距以调整其间距,则可能会在项目中看到更改。

如果此更改导致您的项目出现任何问题,我们建议迁移到 Flex 或 grid 布局,并使用gap

-<div class="space-y-4 p-4">
+<div class="flex flex-col gap-4 p-4">
  <label for="name">Name</label>
  <input type="text" name="name" />
</div>

Using variants with gradients 使用带有渐变的变体

在 v3 中,用变体覆盖渐变的一部分会 “重置” 整个渐变,因此在此示例中,to-\* 颜色在深色模式下将是透明的,而不是黄色的:

<div class="bg-gradient-to-r from-red-500 to-yellow-400 dark:from-blue-500">
  <!-- ... -->
</div>

在 v4 中,这些值被保留,这与 Tailwind 中的其他程序属性的工作方式更加一致。

这意味着,如果您想将三档渐变“取消设置”回特定状态下的两档渐变,则可能需要显式使用via-none

<div class="bg-linear-to-r from-red-500 via-orange-400 to-yellow-400 dark:via-none dark:from-blue-500 dark:to-teal-400">
  <!-- ... -->
</div>

Container configuration 容器配置

在 v3 中, container程序属性具有多个配置选项,例如centerpadding,这些选项在 v4 中已不存在。

要在 v4 中自定义container程序属性,请使用@utility指令对其进行扩展:

@utility container {
  margin-inline: auto;
  padding-inline: 2rem;
}

Default border color 默认边框颜色

在 v3 中,border-*divide-* 程序属性默认使用您配置的gray-200 颜色。我们在 v4 中将其更改为 currentColor,以使 Tailwind 不那么固执己见并匹配浏览器默认值。

要针对此更改更新项目,请确保使用 border-*divide-* 程序属性在任意位置指定颜色:

<div class="border border-gray-200 px-2 py-3 ...">
  <!-- ... -->
</div>

或者,将这些基本样式添加到您的项目中以保留 v3 行为:

@layer base {
  *,
  ::after,
  ::before,
  ::backdrop,
  ::file-selector-button {
    border-color: var(--color-gray-200, currentColor);
  }
}

Default ring width and color

官方已将ring 程序属性的宽度从 3px 更改为 1px,并将默认颜色从 blue-500 更改为 currentColor,以使 border-*divide-*outline-* 程序属性更加一致。

要针对这些更改更新您的项目,请将 ring 的任何用法替换为 ring-3

-<button class="focus:ring ...">
+<button class="focus:ring-3 ...">
  <!-- ... -->
</button>

然后确保根据默认环颜色在你所在的任何位置添加ring-blue-500

<button class="focus:ring-3 focus:ring-blue-500 ...">
  <!-- ... -->
</button>

或者,将这些主题变量添加到您的 CSS 中以保留 v3 行为:

@theme {
  --default-ring-width: 3px;
  --default-ring-color: var(--color-blue-500);
}

请注意,这些变量仅出于兼容性原因而受支持,不被视为 Tailwind CSS v4.0 的惯用用法。

Preflight changes

我们在 v4 的 Preflight 中对基本样式进行了一些小的更改:

New default placeholder color 新的默认占位符颜色

在 v3 中,占位符文本默认使用您配置的 gray-400 颜色。我们在 v4 中对此进行了简化,仅使用不透明度为 50% 的当前文本颜色。

你甚至可能不会注意到这个变化(它甚至可能让你的项目看起来更好),但如果你想保留 v3 的行为,请将这个 CSS 添加到你的项目中:

@layer base {
  input::placeholder,
  textarea::placeholder {
    color: var(--color-gray-400);
  }
}

Buttons use the default cursor 按钮使用默认光标

按钮现在使用 cursor: default 而不是 cursor: pointer 来匹配默认浏览器行为。

如果你想默认继续使用 cursor: pointer,请将这些基本样式添加到你的 CSS 中:

@layer base {
  button:not(:disabled),
  [role="button"]:not(:disabled) {
    cursor: pointer;
  }
}

Dialog margins removed 删除对话边距

现在可以重置 <dialog> 元素的边距,使其与其他元素的重置方式一致。

如果您仍希望对话框在默认情况下居中,请将此 CSS 添加到您的项目中:

@layer base {
  dialog {
    margin: auto;
  }
}

Using a prefix 使用前缀

前缀现在看起来像变体,并且始终位于类名的开头:

<div class="tw:flex tw:bg-red-500 tw:hover:bg-red-600">
  <!-- ... -->
</div>

使用前缀时,您仍应配置主题变量,就像您没有使用前缀一样:

@import "tailwindcss" prefix(tw);
@theme {
  --font-display: "Satoshi", "sans-serif";
  --breakpoint-3xl: 120rem;
  --color-avocado-100: oklch(0.99 0 0);
  --color-avocado-200: oklch(0.98 0.04 113.22);
  --color-avocado-300: oklch(0.94 0.11 115.03);
  /* ... */
}

生成的 CSS 变量将包含一个前缀,以避免与项目中的任何现有变量发生冲突:

:root {
  --tw-font-display: "Satoshi", "sans-serif";
  --tw-breakpoint-3xl: 120rem;
  --tw-color-avocado-100: oklch(0.99 0 0);
  --tw-color-avocado-200: oklch(0.98 0.04 113.22);
  --tw-color-avocado-300: oklch(0.94 0.11 115.03);
  /* ... */
}

Adding custom utilities 添加自定义程序属性

在 v3 中,在 @layer utilities@layer components中定义的任何自定义类都将被 Tailwind 作为真正的程序属性类选取,并将自动与 hoverfocuslg 等变体一起使用,区别在于 @layer components 在生成的样式表中始终排在第一位。

在 v4 中,我们使用原生级联层,不再劫持 @layer 规则,因此我们引入了 @utility API 作为替代:

-@layer utilities {
-  .tab-4 {
-    tab-size: 4;
-  }
-}
+@utility tab-4 {
+  tab-size: 4;
+}

自定义程序属性现在也根据它们定义的属性数量进行排序。这意味着像这样的 .btn 组件程序属性可以被其他 Tailwind 程序属性覆盖,而无需额外配置:

-@layer components {
-  .btn {
-    border-radius: 0.5rem;
-    padding: 0.5rem 1rem;
-    background-color: ButtonFace;
-  }
-}
+@utility btn {
+  border-radius: 0.5rem;
+  padding: 0.5rem 1rem;
+  background-color: ButtonFace;
+}

有关注册自定义程序属性的更多信息,请参阅添加自定义程序属性文档

Variant stacking order

在 v3 中,堆叠变体是从右到左应用的,但在 v4 中,我们更新了它们,使其从左到右应用,看起来更像 CSS 语法。

要针对此更改更新项目,请反转项目中任何顺序敏感的堆叠变体的顺序:

-<ul class="py-4 first:*:pt-0 last:*:pb-0">
+<ul class="py-4 *:first:pt-0 *:last:pb-0">
  <li>One</li>
  <li>Two</li>
  <li>Three</li>
</ul>

如果有的话,你可能只有很少的这些——直接子变体 (*) 和任何排版插件变体( prose-headings )是你可能最有可能使用的,即使这样,也只有在你将它们与其他变体堆叠在一起时。

任意值的变量

在 v3 中,您可以不使用 var() 将 CSS 变量用作任意值,但最近对 CSS 的更新意味着这通常是模棱两可的,因此我们在 v4 中更改了语法,以使用括号而不是方括号。

要针对此更改更新项目,请将旧的变量速记语法替换为新的变量速记语法:

-<div class="bg-[--brand-color]"></div>
+<div class="bg-(--brand-color)"></div>

Hover styles on mobile

在 v4 中,我们更新了 hover 变体,仅在主输入设备支持 hover 时适用:

@media (hover: hover) {
  .hover\:underline:hover {
    text-decoration: underline;
  }
}

如果您以依赖于触摸设备触发点击悬停的方式构建网站,这可能会产生问题。如果这对您来说是一个问题,您可以使用自己的使用旧实现的变体覆盖 hover 变体:

@custom-variant hover (&:hover);

不过,一般来说,我们建议将悬停功能视为一种增强功能,而不是依赖它来使您的网站正常工作,因为触摸设备并不真正具有悬停功能。

Transitioning outline-color

transitiontransition-color 程序属性现在包括 outline-color 属性。

这意味着,如果您添加的轮廓具有焦点上的自定义颜色,您将看到从默认颜色开始的颜色过渡。为避免这种情况,请确保无条件地设置轮廓颜色,或者为两种状态显式设置它:

-<button class="transition hover:outline-2 hover:outline-cyan-500"></button>
+<button class="outline-cyan-500 transition hover:outline-2"></button>

Disabling core plugins

在 v3 中,有一个 corePlugins 选项,你可以用它来完全禁用框架中的某些工具。v4 中不再支持此功能。

Using the theme() function

由于 v4 包含所有主题值的 CSS 变量,因此我们建议尽可能使用这些变量而不是 theme() 函数:

.my-class {
-  background-color: theme(colors.red.500);
+  background-color: var(--color-red-500);
}

对于您仍然需要使用 theme() 函数的情况(例如在不支持 CSS 变量的媒体查询中),您应该使用 CSS 变量名称而不是旧的点表示法:

-@media (width >= theme(screens.xl)) {
+@media (width >= theme(--breakpoint-xl)) {
  /* ... */
}

Using a JavaScript config file

JavaScript 配置文件仍受支持以实现向后兼容性,但在 v4 中不再自动检测到它们。

如果您仍然需要使用 JavaScript 配置文件,则可以使用 @config 指令显式加载它:

@config "../../tailwind.config.js";

基于 JavaScript 的配置中的 corePluginssafelistseparator 选项在 v4.0 中不受支持。要在 v4 中将程序属性列入安全列表,请使用 @source inline

Theme values in JavaScript

在 v3 中,我们导出了一个 resolveConfig 函数,您可以使用该函数将基于 JavaScript 的配置转换为可在其他 JavaScript 中使用的平面对象。

我们在 v4 中删除了这一点,希望人们可以使用我们直接生成的 CSS 变量,这要简单得多,并且会显着减少您的捆绑包大小。

例如,流行的 React Motion 库允许你对 CSS 变量值进行动画处理:

<motion.div animate={{ backgroundColor: 'var(--color-blue-500)' }} />

如果需要访问 JS 中解析的 CSS 变量值,可以使用 getComputedStyle 获取文档根上主题变量的值:

let styles = getComputedStyle(document.documentElement)
let shadow = styles.getPropertyValue('--shadow-xl')

Using @apply with Vue, Svelte, or CSS modules

在 v4 中,与主 CSS 文件(e.g. CSS 模块文件、Vue、Svelte 或 Astro 中的 <style> 块等)分开捆绑的样式表无权访问其他文件中定义的主题变量、自定义程序属性和自定义变体。

要使这些定义在这些上下文中可用,请使用 @reference导入它们,而无需在捆绑包中复制任何 CSS:

<template>
  <h1>Hello world!</h1>
</template>
<style>
+  @reference "../../app.css";
  h1 {
    @apply text-2xl font-bold text-red-500;
  }
</style>

或者,您可以直接使用 CSS 主题变量,而不是完全使用 @apply,这也将提高性能,因为 Tailwind 不需要处理这些样式:

<template>
  <h1>Hello world!</h1>
</template>
<style>
  h1 {
+    color: var(--text-red-500);
  }
</style>

您可以找到有关将 Tailwind 与 CSS 模块结合使用的更多文档。

Using Sass, Less, and Stylus

Tailwind CSS v4.0 不是为与 Sass、Less 或 Stylus 等 CSS 预处理器一起使用而设计的。将 Tailwind CSS 本身视为您的预处理器 — 您不应该将 Tailwind 与 Sass 一起使用,原因与不将 Sass 与 Stylus 一起使用的原因相同。因此,不能将 Sass、Less 或 Stylus 用于样式表,也不能在 Vue、Svelte、Astro 等中使用 <style> 块。

兼容性文档中了解更多信息。