解决 WooCommerce 与 FSE Block Theme 的 4 个 CSS 冲突
在为客户开发 WordPress FSE Block Theme 并集成 WooCommerce 时,遇到 4 个 WooCommerce 静默篡改主题样式的陷阱。每个都很隐蔽,排查耗时。记录根因与解法,帮助同样开发 FSE + WooCommerce 主题的开发者避坑。
TL;DR
- 字号预设覆盖:WooCommerce 注册
small/medium/large/x-large四个预设覆盖 theme.json,用h-1~h-6自定义 slug 规避 - font-size class 连字符:
has-h-1-font-size(48px) vshas-h1-font-size(20px),手写 HTML 必须带连字符 - contrast 颜色反转:
--wp--preset--color--contrast被 WooCommerce 改为浅色(#f8fafc),白色文字完全不可见 - ul.products 伪元素:WooCommerce 注入
::before/::after破坏 CSS Grid 布局,需display:none清除
陷阱一:字号预设被覆盖
问题现象
在 theme.json 中定义了字号预设:
{
"settings": {
"typography": {
"fontSizes": [
{ "slug": "small", "size": "0.875rem" },
{ "slug": "large", "size": "1.125rem" }
]
}
}
}
安装 WooCommerce 后,使用 has-large-font-size 的段落实际渲染为 36px,而非预期的 18px。H1 标题也可能从 48px 缩水到 20px。
根因
WooCommerce 通过 WP_Theme_JSON_API 注册自己的字号预设:
| slug | theme.json 原值 | WooCommerce 覆盖值 |
|---|---|---|
| small | 0.875rem (14px) | 13px |
| medium | 1rem (16px) | 20px |
| large | 1.125rem (18px) | 36px |
| x-large | 1.25rem (20px) | 42px |
同 slug 的预设会被 WooCommerce 的值覆盖。但自定义 slug(如 h-1~h-6、base)不受影响。
解法
theme.json 使用自定义 slug,避免与 WooCommerce 冲突:
{
"fontSizes": [
{ "slug": "h-1", "size": "3rem" },
{ "slug": "h-2", "size": "2.25rem" },
{ "slug": "h-3", "size": "1.75rem" },
{ "slug": "base", "size": "16px" }
]
}
模板中用 has-h-5-font-size 代替 has-large-font-size。
如果需要用到 WooCommerce 的字号值,在 woocommerce.css 顶部定义自定义变量:
:root {
--cclee-font-sm: 13px;
--cclee-font-md: 20px;
--cclee-font-lg: 36px;
--cclee-font-xl: 42px;
}
陷阱二:font-size class 的连字符陷阱
问题现象
手写 FSE 模板 HTML 时,H1 标题只显示 20px 而非 theme.json 定义的 48px:
<!-- 错误:渲染为 20px -->
<h1 class="has-h1-font-size">标题</h1>
<!-- 正确:渲染为 48px -->
<h1 class="has-h-1-font-size">标题</h1>
两个 class 只差一个连字符,但字号差 2.4 倍。
根因
Gutenberg 将 fontSize: "h1" slug 渲染为 has-h-1-font-size(slug 中的数字前加连字符)。这是正确行为。
但当 WooCommerce 覆盖了字号系统后,has-h1-font-size(无连字符)匹配到的是 WooCommerce 的覆盖值(20px),而 has-h-1-font-size(有连字符)匹配到 theme.json 原始值(48px)。
验证方法 -- 浏览器控制台:
// 创建临时元素测试
const el = document.createElement('div');
document.body.appendChild(el);
el.className = 'has-h1-font-size';
console.log('无连字符:', getComputedStyle(el).fontSize); // 20px(错误)
el.className = 'has-h-1-font-size';
console.log('有连字符:', getComputedStyle(el).fontSize); // 48px(正确)
document.body.removeChild(el);
解法
手写 FSE 模板 HTML 时,font-size class 必须带连字符:
<!-- wp:heading {"fontSize":"h1"} -->
<h1 class="has-h-1-font-size">标题</h1>
<!-- /wp:heading -->
<!-- wp:heading {"fontSize":"h3"} -->
<h2 class="has-h-3-font-size">区块标题</h2>
<!-- /wp:heading -->
规则:has-h-{N}-font-size(带连字符),适用于所有 h-* 预设。
陷阱三:contrast 颜色反转
问题现象
在 contrast 背景色上使用 base(白色)文字,发现文字完全不可见:
<div class="has-contrast-background-color">
<h2 class="has-base-color">白色标题在深色背景上</h2>
</div>
预期 contrast 是深色背景 + 白色文字,实际 contrast 是浅色背景。
根因
WooCommerce 将 --wp--preset--color--contrast 注册为 #f8fafc(极浅灰),不是深色。这是 WooCommerce 的设计意图(其默认主题用 contrast 做浅色背景区域),但与大多数 FSE 主题的 contrast 语义(深色)冲突。
解法
contrast 背景上用 primary(深色)作为文字颜色:
<div class="has-contrast-background-color">
<h2 class="has-primary-color has-text-color">深色标题在浅色背景上</h2>
</div>
或者在 theme.json 中定义自己的深色 preset(如 surface),不依赖 contrast:
{
"settings": {
"color": {
"palette": [
{ "slug": "surface", "color": "#0f172a", "name": "Surface" }
]
}
}
}
陷阱四:ul.products 伪元素破坏 Grid 布局
问题现象
WooCommerce 商品列表使用 CSS Grid 布局时,卡片排列错位、多出空白格:
ul.products {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
预期 3 列等宽,实际出现空位,部分卡片换到下一行。
根因
WooCommerce 在 ul.products 上注入了 ::before 和 ::after 伪元素:
ul.products::before,
ul.products::after {
display: table;
content: '';
}
ul.products::after {
clear: both;
}
这些伪元素是为传统 float 布局设计的 clearfix。但 CSS Grid 把伪元素当作 grid items,占用了两个隐式格子位。
解法
对 Grid 布局的 ul.products 隐藏伪元素:
ul.products {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
ul.products::before,
ul.products::after {
display: none;
}
注意事项
- 每个陷阱都与 WooCommerce 的
WP_Theme_JSON_API注册或 CSS 注入有关,禁用 WooCommerce 后这些覆盖会消失 - 陷阱一和二是联动的:WooCommerce 覆盖字号预设后,连字符和无连字符的 class 映射到不同值
- 陷阱三的 contrast 值取决于 WooCommerce 版本,升级后可能变化,建议用自定义 slug(如
surface)代替 - 手写 FSE 模板前,先用浏览器 DevTools 检查 Gutenberg 自动渲染的 class 名称,不要想当然地缩写

