升级 tailwind v4 的一次样式 BUG 修复记录

标签:tailwind, CSS
分类:TOOL
6分钟阅读51a304f3
概述:
创建:
Published On

背景

tailwind v4 中,对于伪元素(::before::after)和状态字段(比如::hover:focus)的顺序约定相比于 v3 而言,是更加符合直觉。

如在 v3 版本中,一个关联伪元素和状态的原子类书写可能是:after:hover:text-white, 而 v4 中的约定(/建议)顺序变更为: hover:after:text-white 来处理普遍情况。

实质上,这样的顺序也更加契合原生 CSS 的写法。

比如:

a.some-link {
  &::after { /.../ }
  &:hover::after {
    color: white;
  }
  /* ... */
}

但是随着版本的升级迭代,也带来了更明确的限制,比如在 v3 版本中:我们可能基于 tailwind @apply 关键字在 css 文件中如此书写:

a.some-link {
  &::after {
    @apply text-red-300 hover:text-white;
  }
}

但是这不能在 v4 中如预期地被编译处理。所以当前更推荐的写法是:

a.some-link {
  &::after {
    @apply text-red-300;
  }
  &:hover::after {
    @apply text-white;
  }
}

当然在官方文档(Using @apply with Vue, Svelte, or CSS modules)中,有这样提及:

Alternatively, you can use your CSS theme variables directly instead of using @apply at all, which will also improve performance since Tailwind won't need to process these styles: 或者,您可以直接使用 CSS 主题变量,而不是使用 @apply,这也将提高性能,因为 Tailwind 不需要处理这些样式

即:

a.some-link {
  &::after {
    color: var(--color-red-300);
  }
  &:hover::after {
    color: var(--color-white);
  }
}

但这并不在本文的讨论范围,下面的例子仍然使用 @apply 关键字。


上面的简要提及,也引出了下面正文一节的,提到的一次笔者处理 tailwind 升级到 v4 版本后的一处不易察觉的样式 bug。

正文

在使用 taiwind 官方升级脚本工具:npx @tailwindcss/upgrade, 尽管处理了项目源码中大多数 tailwind 原子类书写变更。但是比如在 .scss/.css 文件中,一些样式声明中,则不能很好的升级变更,比如以下一段代码(其是处理代码块右上角语言水印戳的样式代码):

pre[data-lang="jsx"] {
  &::after {
    @apply bg-[#f0db4f] text-black md:bg-transparent md:text-muted-foreground/20;
  }
}

以上的一段代码在 v3 版本中,能够如预期的应用样式。但是在 v4 中却失效了,原因可能就是前文提及的对顺序的强约定性,尽管 v3 版本中,关于媒体断点和伪元素的共同出现时顺序和 v4 版本保持了一致性,即: md:before:text-current, 但是 v4 的编译处理有所变化。

并且就以上面的(本质是当前 v4 版本下错误的/ 非推荐的)代码段的编译结果为例:

(并且经笔者验证,这个编译产物在开发模式和生产模式有明显的差异,所以也就导致了在开发模式下出现非预期的样式声明失效,而生产部署模式下样式又正常如旧的情况)

开发模式下的编译产物

generated-css-on-dev-mode
.md-prose-cus pre[data-lang=jsx]:after {
  background-color: #f0db4f; // it also works on above md(48rem) breakpoint...
  color: var(--color-black);
  @media (width >= 48rem) {
    background-color: transparent; // BUT NOT WORKING!
  }
  @media (width >= 48rem) {
    color: var(--muted-foreground);
    @supports (color: color-mix(in lab, red, red)) {
      color: color-mix(in oklab, var(--muted-foreground) 20%, transparent); // BUT NOT WORKING!
    }
  }
}

生产模式下的编译产物

generated-css-on-production-mode
.md-prose-cus pre[data-lang="jsx"]:after {
    color: var(--color-black);
    background-color: #f0db4f;
  }
@media (min-width: 48rem) {
  .md-prose-cus pre[data-lang="jsx"]:after {
    color: var(--muted-foreground);
    background-color: #0000;
  }
  @supports (color: color-mix(in lab, red, red)) {
    .md-prose-cus pre[data-lang="jsx"]:after {
      color: color-mix(in oklab, var(--muted-foreground) 20%, transparent);
    } // YEAN, it WORKS
  }
}

为何在开发模式下生成 css 样式失效?原因就在于此时“错误的”嵌套层级。

而如果一定需要在单独的 css 文件中结合 @apply 定义样式,那么上面的代码使样式符合预期被应用的写法是:

pre[data-lang="jsx"] {
  @apply after:bg-[#f0db4f] after:text-black after:content-[attr(data-lang)] md:after:bg-transparent md:after:text-muted-foreground/20;
}

小结

一个并不算严谨的总结,在我们了解了 tailwind 对部分原子类有约定顺序后,比如:md:hover:before:text-current, 那么在结合 @apply 书写 css 时,

比如当 css 嵌套层级下的顺序等同于:after:md:[atom-clz] (即上面的代码例)、after:hover:[atom-clz] 时,并且此时样式的应用不符合预期时,可从这个角度去核验样式的声明是否可以变更,

以让其 css 嵌套层级下的等同顺序:符合官方(多数情况下)建议的:md:after:[atom-clz]hover:after:[some-clz]

升级 tailwind v4 的一次样式 BUG 修复记录

https://infen.cc/loc-blog/35_tailwind-v4-some-detail-on-pseudo-ele[Copy]
本文作者
Hyperiop
创建/发布于
Published On
更新/发布于
Updated On
许可协议
CC BY-NC-SA 4.0

转载或引用本文时请遵守“署名-非商业性使用-相同方式共享 4.0 国际”许可协议,注明出处、不得用于商业用途!分发衍生作品时必须采用相同的许可协议。