微信小程序 + Taro + TDesign 去掉 [&&&],让普通 Tailwind 类接管局部样式

微信小程序 + Taro + TDesign 去掉 [&&&],让普通 Tailwind 类接管局部样式

在微信小程序里把 Taro Text 替换成 TDesign 的 t-text 后,页面间距突然变大了。继续检查,还能发现字号、行高和颜色也不完全一致。

原因并不复杂:原来的 Text 没有额外的排版边距,字体样式主要继承父级;TDesign 文本组件则自带默认样式:

css 复制代码
.t-typography {
  color: var(--td-text-color-primary, ...);
  font: var(--td-font-body-medium, ...);
  margin: var(--td-spacer-2, 32rpx) 0;
}

默认上下各 32rpx 的边距,放进原本紧凑的列表后就很明显。

我最开始用全局规则恢复原来的排版:

css 复制代码
.t-typography.t-typography {
  margin: 0;
  font: inherit;
  color: inherit;
}

它能压过组件默认值,却又带来了新的问题:普通 Tailwind 类只有一个类选择器,覆盖不了这个双类选择器。于是页面里开始出现这样的写法:

tsx 复制代码
<t-text t-class="[&&&]:mt-[12rpx]" ellipsis>
  {content}
</t-text>

[&&&] 会让生成的选择器重复三次,以提高优先级。这个办法能用,但全局默认值本来应该容易覆盖,现在却要求每个局部样式都主动提高优先级,方向反了。

解决方案

这次调整的目标是让三个文本组件统一使用应用默认排版,页面里的差异直接交给普通 Tailwind 类:

tsx 复制代码
<t-text t-class="mt-[12rpx]" ellipsis>
  {content}
</t-text>

这里需要同时处理两处样式来源:

  • 应用自己的全局排版规则。
  • TDesign 文本组件 WXSS 中的基础排版规则。

只把全局规则改成单类选择器还不够。组件自身仍然声明了 font、margin 和 color,这些规则也会参与覆盖。

项目最终采用的做法是:在现有资源复制环节移除三个文本组件的基础排版规则,再由 Tailwind base 层统一提供默认值。

项目环境

这次调整发生在 Taro React 微信小程序项目中,使用的版本是:

依赖 版本
Taro 4.3.2
TDesign Miniprogram 1.17.0
Tailwind CSS 4.3.4
weapp-tailwindcss 5.6.3

项目已经通过 Taro 的 copy.patterns 复制 TDesign 资源,并安装了 PostCSS。下面的配置沿用这套构建链路,没有修改 node_modules 中的依赖源码。

在复制资源时处理组件默认样式

修改 apps/miniprogram/config/index.ts,增加 PostCSS 导入:

ts 复制代码
import postcss from "postcss"

项目已有的 tdesignRuntimeDirectories 包含 text、title 和 paragraph。在对应的主包资源复制配置中增加 transform:

ts 复制代码
...tdesignRuntimeDirectories.map((directory) => ({
  from: `node_modules/tdesign-miniprogram/miniprogram_dist/${directory}`,
  to: `dist/npm/tdesign-miniprogram/${directory}`,
  ignore: [
    "**/*.d.ts",
    "**/*.map",
    "**/shared/calendar/**",
    "**/shared/color-picker/**",
    "**/shared/qrcode/**",
  ],
  transform(content: Buffer, absoluteFrom: string) {
    if (
      !["text", "title", "paragraph"].includes(directory) ||
      path.basename(absoluteFrom) !== `${directory}.wxss`
    ) {
      return content
    }

    const stylesheet = postcss.parse(content.toString(), {
      from: absoluteFrom,
    })

    stylesheet.walkRules((rule) => {
      if (/^\.t-typography(?:--h[1-6])?$/.test(rule.selector)) {
        rule.remove()
      }
    })

    return stylesheet.toString()
  },
})),

这段配置只处理三个组件各自的入口 WXSS,移除:

css 复制代码
.t-typography
.t-typography--h1
.t-typography--h2
.t-typography--h3
.t-typography--h4
.t-typography--h5
.t-typography--h6

主题、装饰、复制和省略相关规则继续保留,其他组件资源原样复制。

这里也有一个明确的取舍:项目不再直接使用 TDesign 标题等级自带的字号和边距,而是由页面用 Tailwind 表达视觉差异。例如,登录标题仍使用 t-title,字号和字重显式配置。

这段适配依赖当前版本的选择器结构。升级 TDesign 时,需要重新核对这些规则,不能默认它永远不变。

将应用默认排版放入 base 层

修改 apps/miniprogram/src/tailwind.css,删除原来的双类选择器,以及为不同文本位置编写的自定义样式类。

默认排版放进已有的 @layer base:

css 复制代码
@layer base {
  .t-typography {
    @apply m-0 [font:inherit] text-inherit;
  }
}

这条规则只负责三件事:

  • 清除默认外边距。
  • 继承父级字体,包括字号、字重和行高。
  • 继承父级颜色。

具体页面需要什么样式,就直接写普通 Tailwind 类:

tsx 复制代码
<t-title
  level="h3"
  t-class="min-w-0 flex-1 text-2xl font-semibold"
>
  {title}
</t-title>

<t-text t-class="mt-[12rpx]" ellipsis>
  {createdAt}
</t-text>

<t-paragraph
  t-class="mb-[16rpx] text-[length:26rpx] text-[color:var(--td-text-color-secondary)]"
>
  {notice}
</t-paragraph>

不再需要 original-text,也不再需要 [&&&]。

小程序里要写 t-class

这次排查还遇到了一个比 CSS 优先级更靠前的问题:外部样式属性没有正确传入组件。

在当前项目的 Taro 编译链路中:

tsx 复制代码
<t-text tClass="mt-[12rpx]">
  {content}
</t-text>

会生成:

xml 复制代码
<t-text tclass="{{i.tClass}}">

而 TDesign 声明的外部样式属性是 t-class。属性名不匹配时,即使 CSS 已经生成,样式也没有通过这个入口传进组件。

因此 JSX 使用连字符写法:

tsx 复制代码
<t-text t-class="mt-[12rpx]">
  {content}
</t-text>

同时,在 apps/miniprogram/config/index.ts 的 weapp-tailwindcss 配置中保留对应的属性识别:

ts 复制代码
customAttributes: {
  "*": [
    "t-class",
    "t-class-content",
    "t-class-title",
    "t-class-description",
    "t-class-center",
    "t-class-note",
    "t-class-label",
    "t-class-right",
    "t-class-left",
  ],
},

这样,Tailwind 类名转换和组件外部样式属性才能接上。

重新构建后检查产物

保存以上文件后,需要重新构建。只在微信开发者工具中重新编译旧的 dist,不会执行资源复制时新增的转换逻辑。

bash 复制代码
cd apps/miniprogram
pnpm build

这次构建成功后,我检查了两部分产物。

三个文本组件的 WXSS 中,基础 .t-typography 和标题等级规则已经移除,其余样式仍然保留。dist/app.wxss 中,全局默认规则排在普通工具类之前:

css 复制代码
.t-typography {
  color: inherit;
  font: inherit;
  margin: 0rpx;
}

/* 后面生成普通工具类 */
.mt-_b12rpx_B {
  margin-top: 12rpx;
}

两者都是单类选择器。在这份产物中,后面的 margin-top 可以覆盖前面的 margin 简写,不需要额外提高优先级。

页面 JS 中的类名也已经完成转换:

js 复制代码
"t-class": "mt-_b12rpx_B"

WXML 使用的则是正确的外部样式属性:

xml 复制代码
<t-text t-class="{{i.tClass}}">

本次编译、TypeScript 和差异检查通过,Lint 无错误,但仍有项目已有警告。这些结果验证了构建链路和样式生成结构;实际微信界面尚未验证,需要重新加载当前 dist,检查登录标题、列表辅助行间距和地图文本的显示效果。

相关推荐
费曼学习法1 小时前
把 3 个内部服务封装成 MCP Server 的工程复盘:进程模型、超时与错误契约
前端
Captaincc1 小时前
转译:《软件工程师现在该怎么办》
前端·后端·ai编程
天才熊猫君1 小时前
给 Vue 的 reactive 套 Proxy,为什么响应式会失灵?
前端·javascript
htzyl2061 小时前
别急着上微前端:从 6 个场景倒推 Module Federation 2.0 与 qiankun 2.x 的选型
前端·微服务
verohh1 小时前
Cesium 多业务页面切换的资源隔离与架构设计:单 Viewer 复用还是多实例隔离
前端
律宏阔1 小时前
微信小程序 + Taro 从 ESLint 迁移到 Oxlint 让项目代码检查速度提升近 12 倍
前端·typescript·eslint
用户30816998764851 小时前
复制的代码为什么报错?BOM 等 10 种隐形字符 40 组实测
前端
Swot2 小时前
SvelteKit 踩坑记:+page.js 里忘了 ...data,服务端数据全没了
前端·后端·svelte
律宏阔2 小时前
微信小程序 + Taro + 多语言实现与国际化检查实录
前端·微信小程序·taro