搜索全站
主题 15 分钟阅读

Tailwind CSS 与 WordPress 主题结合:构建流程与按需裁剪

Tailwind 写 WordPress 主题很爽,但真上线会遇到:动态类名被 purge 掉、preflight 把编辑器样式清了、区块默认样式被覆盖。本文给出完整的构建配置、content 扫描范围、safelist 与编辑器样式处理方案。

U
UFO_PF 2024-02-23 · 阅读 15 分钟
Ta 主题
阅读提示
本文约 5,982 字,预计阅读 15 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:写得快,上线就翻车

用 Tailwind 写 WordPress 模板的体验确实好:不用在 SCSS 文件之间跳来跳去,直接在 class 里堆 flex items-center gap-4 text-sm text-gray-600 就能出效果。问题往往出现在打包后——本地开发好好的,构建产物里某些类不见了;或者更隐蔽的:后台编辑器里按钮没有边框、列表没有圆点,因为 Tailwind 的 preflight 把浏览器默认样式(连带区块编辑器依赖的一部分)重置了。

这两个坑的本质是同一件事:Tailwind 是一个「按需生成」的构建工具,它只认静态出现在源码里的类名;而 WordPress 的类名大量来自 PHP 运行时拼接与核心样式表。把这两者的边界理清楚,Tailwind 才能真正用在生产项目上。

原理分析:三个必须解决的冲突

冲突一:purging 与动态类名。 Tailwind 扫描 content 里指定的文件,用正则提取可能的类名字符串,只生成命中的那部分 CSS。如果类名是运行时拼出来的(col-span-{{ $n }}、<?php echo $align === 'left' ? 'text-left' : 'text-right'; ?>),扫描器看不到最终字符串,产物里就没有对应规则。解决办法是 safelist(白名单)或用完整的静态类名分支。

冲突二:preflight 与编辑器/内容区。 preflight 重置了 ul { list-style: none }、h1 { font-size: inherit }、button { background: transparent } 等。这在你自己的组件里是好事,但区块编辑器输出的内容(.wp-block-list、.wp-block-quote)依赖核心样式与主题补充样式,一重置就「散架」。处理方式有三:关闭 preflight、只在自己写的结构里用 Tailwind、或给内容区单独补一套排版样式(@tailwindcss/typography 的 prose 是常见选择)。

冲突三:与 theme.json / 区块默认样式的优先级。 区块主题会输出全局样式(CSS 变量与类名),Tailwind 的工具类优先级(单层类)常常打不过 .wp-block-button__link 这种带层级的规则。需要时用 @layer 或提高选择器权重,别靠 !important 硬来(AMP 环境下 !important 还会导致验证失败,见 AMP 与移动适配)。

保姆级实操

第一步:初始化构建链

cd wp-content/themes/mimangfei
npm init -y
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init

tailwind.config.js(Tailwind v3):

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: [
        './**/*.php',
        './template-parts/**/*.php',
        './inc/**/*.php',
        './js/**/*.js',
    ],
    theme: {
        extend: {
            colors: {
                brand: {
                    DEFAULT: '#2563eb',
                    dark: '#1d4ed8',
                },
                ink: '#1a1a1a',
            },
            maxWidth: {
                content: '720px',
                container: '1200px',
            },
            fontFamily: {
                sans: [ 'system-ui', '-apple-system', 'PingFang SC', 'Microsoft YaHei', 'sans-serif' ],
            },
        },
    },
    plugins: [
        require( '@tailwindcss/typography' ),
    ],
};

content 一定要覆盖所有可能写类名的 PHP 文件,包括 template-parts/ 与 inc/。漏掉某个目录的表现是「只有那个目录的模板样式失效」。

Tailwind v4 改为 CSS 优先配置,写法不同:

@import "tailwindcss";

@theme {
    --color-brand: #2563eb;
    --color-ink: #1a1a1a;
    --font-sans: system-ui, -apple-system, "PingFang SC", sans-serif;
}

第二步:入口样式文件

/* src/input.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
    body {
        @apply text-ink antialiased;
    }
    /* preflight 重置后,给内容区补回列表与引用样式 */
    .entry-content ul { @apply list-disc pl-6 my-4; }
    .entry-content ol { @apply list-decimal pl-6 my-4; }
    .entry-content blockquote { @apply border-l-4 border-brand pl-4 italic my-6; }
}

第三步:PostCSS 与构建脚本

// postcss.config.js
module.exports = {
    plugins: {
        tailwindcss: {},
        autoprefixer: {},
    },
};
{
  "scripts": {
    "dev": "tailwindcss -i ./src/input.css -o ./assets/css/app.css --watch",
    "build": "NODE_ENV=production tailwindcss -i ./src/input.css -o ./assets/css/app.css --minify"
  }
}

Windows 下 NODE_ENV=production 语法不兼容,改用 cross-env 或在 package.json 里写 "build:win": "set NODE_ENV=production && tailwindcss ..."。

第四步:在主题里加载产物

add_action( 'wp_enqueue_scripts', 'mimangfei_assets' );

function mimangfei_assets() {
    wp_enqueue_style(
        'mimangfei-app',
        get_template_directory_uri() . '/assets/css/app.css',
        array(),
        wp_get_theme()->get( 'Version' )
    );
}

版本号用主题版本或 filemtime(),避免改了样式用户端还命中旧缓存:

$css_path = get_template_directory() . '/assets/css/app.css';
$css_ver  = file_exists( $css_path ) ? filemtime( $css_path ) : wp_get_theme()->get( 'Version' );

第五步:编辑器里也要有同样的样式

add_action( 'after_setup_theme', function() {
    add_theme_support( 'editor-styles' );
    add_editor_style( 'assets/css/editor.css' );
} );

建议单独出一个 editor.css(入口为 src/editor.css,content 里只包含 base + typography,不含 preflight 的重置部分),避免后台样式把编辑器自身的 UI 打乱:

/* src/editor.css */
@tailwind components;
@tailwind utilities;

第六步:处理动态类名

<?php
// 不推荐:类名被拼接,Tailwind 扫不到
printf( '<div class="col-span-%d">', absint( $columns ) );

// 推荐:完整的静态类名分支
$col_class = array(
    2 => 'md:grid-cols-2',
    3 => 'md:grid-cols-3',
    4 => 'md:grid-cols-4',
);
$class = isset( $col_class[ $columns ] ) ? $col_class[ $columns ] : 'md:grid-cols-3';
printf( '<div class="grid gap-6 %s">', esc_attr( $class ) );

确实无法避免时用 safelist:

module.exports = {
    content: [ './**/*.php' ],
    safelist: [
        'md:grid-cols-2',
        'md:grid-cols-3',
        'md:grid-cols-4',
        {
            pattern: /^(bg|text)-(brand|ink|gray)-(100|200|500|700)$/,
            variants: [ 'hover', 'focus' ],
        },
    ],
};

safelist 会显著增大产物体积,只加真正需要的那一组,不要图省事用宽泛的正则。

第七步:按需裁剪与体积检查

npm run build
ls -la assets/css/app.css

一个中型企业站的 Tailwind 产物通常在 20–60KB(gzip 后 6–12KB),若超过 150KB 说明 safelist 过宽或 content 扫描范围把 node_modules 也扫进去了。用 npx tailwindcss -i src/input.css -o /dev/null --content "./**/*.php" 配合 --minify 的产物体积对比可快速定位。

常见踩坑

  1. content 只写了 ./**/*.html:WordPress 没有 HTML 模板,产物几乎为空,页面裸奔。
  2. 动态类名被 purge:本地 npm run dev 时 Tailwind 的 JIT 会生成更多类,构建后消失,务必用生产产物验证一遍关键页面。
  3. preflight 清掉了编辑器内容样式:列表无圆点、引用无线条,用 @layer base 补回或引入 prose。
  4. 与区块核心样式打架:按钮样式被 .wp-block-button__link 覆盖,需要在 components 层针对区块类名写规则。
  5. 把 node_modules 与 vendor 扫进 content:产物体积暴涨且生成大量无用类,用 .gitignore 之外的显式路径列表。
  6. 案例:某外贸站用 Tailwind 重做主题后,产品列表的「三列/四列」切换在开发环境正常,上线后所有页面都变成单列。原因是模板里用 'grid-cols-' . $cols 拼接类名,生产构建时被 purge。修复方式是把可选类名写成完整字符串的映射数组,并对历史数据里已保存的列数值做兜底映射。
  7. 编辑器样式用了带 preflight 的同一份产物:后台编辑器的按钮、输入框被重置,看起来像后台坏了。
  8. 忘记提交构建产物:Git 忽略 assets/css/app.css,部署后样式为空,应在部署脚本里执行 npm run build,或明确把产物纳入版本管理。

总结

落地顺序:先定 content 扫描范围与产物入口 → 写 @layer base 补回内容区基础排版 → 编辑器单独出一份 CSS → 再处理动态类名(优先静态分支,其次 safelist)→ 最后用生产产物逐页验证。Tailwind 与 WordPress 并不冲突,冲突的是「按需生成」与「运行时拼类名」这两种思维。若你的项目是区块主题,建议把设计 token 放进 theme.json 全局样式 与 Tailwind 的 theme.extend 保持同步,避免两套颜色定义各自漂移;若是经典主题,可配合 用 Underscores 从零做主题 的骨架一起用。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。