Tailwind CSS 在 Typecho 中的完整教程


📚 教程目录

  1. Tailwind CSS 是什么?
  2. 环境准备与安装
  3. 基础配置
  4. 在主题中使用
  5. 响应式设计
  6. 暗黑模式
  7. 与 project_rules.md 结合
  8. 常见问题

一、Tailwind CSS 是什么?

Tailwind CSS 是一个实用优先(Utility-first)的 CSS 框架。和传统框架(如 Bootstrap)提供预定义组件(.btn.card)不同,Tailwind 提供的是原子化的工具类:

/* 传统写法 */
.btn-primary {
  background: #20a53a;
  color: white;
  padding: 10px 20px;
  border-radius: 4px;
}

/* Tailwind 写法 - 直接在 HTML 中使用工具类组合 */
<button class="bg-green-600 text-white px-4 py-2 rounded">
  按钮
</button>

✨ 核心优势

特性说明
开发效率无需写 CSS,直接在 HTML 中组合类名
体积小构建时自动删除未使用的类,最终 CSS 文件极小
无命名冲突不需要担心类名重复
响应式内置md:lg: 前缀轻松实现响应式
可定制性强通过配置文件自定义主题

二、环境准备与安装

2.1 两种安装方式对比

方式适用场景优点缺点
CDN 方式快速测试、小工具无需配置,直接可用体积大(~3MB),无法定制
构建方式正式主题、长期维护按需编译,可定制,体积小需要 Node.js 环境

推荐:正式项目使用构建方式,符合 project_rules.md 的规范要求。

2.2 构建方式安装步骤

步骤1:进入主题目录

cd usr/themes/your-theme-name

步骤2:初始化 npm 项目

npm init -y

步骤3:安装 Tailwind CSS 及依赖

npm install -D tailwindcss postcss autoprefixer cssnano
注:postcssautoprefixer 是 Tailwind 的必备依赖

步骤4:初始化 Tailwind 配置

npx tailwindcss init -p

这个命令会创建两个文件:

  • tailwind.config.js - Tailwind 主配置文件
  • postcss.config.js - PostCSS 配置文件

三、基础配置

3.1 配置 tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  // 告诉 Tailwind 扫描哪些文件中的类名
  content: [
    './*.php',
    './templates/**/*.php',
    './assets/js/**/*.js',
    '../../plugins/**/*.php',  // 如果需要扫描插件
  ],
  theme: {
    extend: {
      // 扩展主题色 - 适配您的宝塔绿色调
      colors: {
        primary: {
          DEFAULT: '#20a53a',
          50: '#f0fdf4',
          100: '#dcfce7',
          500: '#20a53a',
          600: '#18802c',
          700: '#166b34',
        },
      },
      // 扩展间距,匹配 project_rules.md 中的 mt-1,2,3
      spacing: {
        '18': '4.5rem',
        '88': '22rem',
      },
    },
  },
  plugins: [],
  // 暗黑模式支持(后面会详细讲)
  darkMode: 'class',
}

3.2 创建主 CSS 文件

在主题目录下创建 style.css(如果已存在则修改):

/* style.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* 自定义组件层 - 复用 project_rules.md 的工具类 */
@layer components {
  /* 卡片组件 */
  .card {
    @apply bg-white rounded-lg shadow-md p-6;
    @apply dark:bg-gray-800 dark:text-white;
  }
  
  .card__header {
    @apply border-b border-gray-200 pb-4 mb-4;
    @apply dark:border-gray-700;
  }
  
  .card__title {
    @apply text-xl font-bold text-gray-900;
    @apply dark:text-gray-100;
  }
  
  /* 按钮组件 */
  .btn-primary {
    @apply px-4 py-2 bg-primary text-white rounded-md;
    @apply hover:bg-primary-600 transition-colors;
    @apply focus:outline-none focus:ring-2 focus:ring-primary-500;
  }
  
  /* 复用 project_rules.md 的工具类 */
  .text-muted {
    @apply text-gray-500 dark:text-gray-400;
  }
  
  .mt-1 {
    @apply mt-1;
  }
  
  .mt-2 {
    @apply mt-2;
  }
  
  .mt-3 {
    @apply mt-3;
  }
}

3.3 配置 package.json 脚本

{
  "scripts": {
    "dev": "npx tailwindcss -i ./style.css -o ./assets/css/style.min.css --watch",
    "build": "npx tailwindcss -i ./style.css -o ./assets/css/style.min.css --minify"
  }
}

3.4 开发流程

# 开发时:监听文件变化,实时编译
npm run dev

# 生产环境:编译并压缩
npm run build

3.5 在主题中引用

header.php 中添加:

<!-- 引用编译后的 CSS 文件 -->
<link rel="stylesheet" href="<?php $this->options->themeUrl('assets/css/style.min.css'); ?>">

四、在主题中使用

4.1 基础用法示例

文章列表卡片

<!-- index.php -->
<div class="container mx-auto px-4 py-8">
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
    <?php while($this->next()): ?>
      <article class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow">
        <!-- 文章缩略图 -->
        <?php if ($this->fields->thumbnail): ?>
          <img src="<?php $this->fields->thumbnail(); ?>" 
               class="w-full h-48 object-cover">
        <?php endif; ?>
        
        <div class="p-6">
          <!-- 标题 -->
          <h2 class="text-xl font-bold mb-2">
            <a href="<?php $this->permalink() ?>" 
               class="hover:text-primary-600 transition-colors">
              <?php $this->title() ?>
            </a>
          </h2>
          
          <!-- 元信息 -->
          <div class="flex items-center text-sm text-muted mb-4">
            <span class="mr-4">
              <svg class="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 
                      d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
              </svg>
              <?php $this->date('Y-m-d'); ?>
            </span>
            <span><?php $this->category(','); ?></span>
          </div>
          
          <!-- 摘要 -->
          <p class="text-muted mb-4 line-clamp-3">
            <?php $this->excerpt(100, '...'); ?>
          </p>
          
          <!-- 阅读更多 -->
          <a href="<?php $this->permalink() ?>" 
             class="inline-flex items-center text-primary hover:text-primary-600">
            阅读更多
            <svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 
                    d="M9 5l7 7-7 7" />
            </svg>
          </a>
        </div>
      </article>
    <?php endwhile; ?>
  </div>
</div>

分页导航

<!-- 分页部分 -->
<div class="flex justify-center mt-8">
  <div class="flex space-x-2">
    <?php $this->pageNav('«', '»', 1, '...', [
      'wrapTag' => 'div',
      'wrapClass' => 'flex space-x-2',
      'itemTag' => 'span',
      'currentClass' => 'px-3 py-2 bg-primary text-white rounded',
      'prevClass' => 'px-3 py-2 border border-gray-300 rounded hover:bg-gray-100',
      'nextClass' => 'px-3 py-2 border border-gray-300 rounded hover:bg-gray-100',
    ]); ?>
  </div>
</div>

评论列表

<!-- comments.php -->
<div class="mt-8">
  <h3 class="text-lg font-bold mb-4">评论</h3>
  
  <?php $this->comments()->to($comments); ?>
  <?php while($comments->next()): ?>
    <div class="flex space-x-4 mb-6 p-4 bg-gray-50 rounded-lg">
      <div class="flex-shrink-0">
        <img src="<?php $comments->gravatar(40); ?>" 
             class="w-10 h-10 rounded-full">
      </div>
      <div class="flex-1">
        <div class="flex items-center justify-between mb-2">
          <span class="font-medium"><?php $comments->author(); ?></span>
          <span class="text-sm text-muted"><?php $comments->date('Y-m-d H:i'); ?></span>
        </div>
        <div class="text-gray-700">
          <?php $comments->content(); ?>
        </div>
      </div>
    </div>
  <?php endwhile; ?>
  
  <!-- 评论表单 -->
  <?php if($this->allow('comment')): ?>
    <form method="post" action="<?php $this->commentUrl() ?>" class="mt-6">
      <h4 class="font-medium mb-4">发表评论</h4>
      
      <?php if(!$this->user->hasLogin()): ?>
        <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
          <input type="text" name="author" placeholder="昵称 *" required
                 class="form-control w-full px-3 py-2 border border-gray-300 rounded-md">
          <input type="email" name="mail" placeholder="邮箱 *" required
                 class="form-control w-full px-3 py-2 border border-gray-300 rounded-md">
          <input type="url" name="url" placeholder="网站"
                 class="form-control w-full px-3 py-2 border border-gray-300 rounded-md">
        </div>
      <?php endif; ?>
      
      <textarea name="text" rows="4" placeholder="评论内容..." required
                class="form-control w-full px-3 py-2 border border-gray-300 rounded-md mb-4"></textarea>
      
      <button type="submit" class="btn-primary">
        提交评论
      </button>
    </form>
  <?php endif; ?>
</div>

4.2 常用工具类速查表

类别Tailwind 类作用
布局container mx-auto居中容器
flexgrid弹性/网格布局
grid-cols-33列网格
gap-4网格间距
间距p-4内边距 1rem
px-4左右内边距
mt-2上外边距 0.5rem
space-x-4子元素水平间距
排版text-xl字体大小 1.25rem
font-bold粗体
text-center居中
line-clamp-3最多3行后省略
颜色text-primary主色文字
bg-gray-100浅灰背景
border-gray-300灰色边框
交互hover:bg-primary-600悬停变深
transition-shadow阴影过渡
cursor-pointer指针样式

五、响应式设计

Tailwind 采用 移动优先(Mobile First) 的响应式策略。断点前缀表示 min-width

前缀断点说明
sm:640px小屏幕
md:768px中等屏幕
lg:1024px大屏幕
xl:1280px超大屏幕
2xl:1536px巨幕

5.1 响应式示例

<div class="
  <!-- 手机:单列,小字体 -->
  grid grid-cols-1 text-sm
  <!-- 平板:两列,中等字体 -->
  md:grid-cols-2 md:text-base
  <!-- 桌面:三列,大字体 -->
  lg:grid-cols-3 lg:text-lg
  <!-- 间距也响应 -->
  gap-4 md:gap-6 lg:gap-8
">
  <!-- 内容 -->
</div>

5.2 复杂响应式示例

<!-- 侧边栏布局:手机垂直,桌面水平 -->
<div class="flex flex-col md:flex-row">
  <!-- 侧边栏:手机占满,桌面固定宽度 -->
  <aside class="
    w-full md:w-64
    bg-gray-50 p-4
    md:bg-transparent
  ">
    侧边栏内容
  </aside>
  
  <!-- 主内容:自适应 -->
  <main class="flex-1 p-4">
    主内容
  </main>
</div>

六、暗黑模式

6.1 启用暗黑模式

tailwind.config.js 中配置:

module.exports = {
  darkMode: 'class',  // 或 'media'(跟随系统)
  // ...
}

6.2 创建暗黑模式切换脚本

在主题中创建 assets/js/theme.js

// theme.js
(function() {
  // 获取保存的主题或跟随系统
  const getTheme = () => {
    const saved = localStorage.getItem('theme');
    if (saved) return saved;
    
    return window.matchMedia('(prefers-color-scheme: dark)').matches 
      ? 'dark' 
      : 'light';
  };
  
  // 应用主题
  const applyTheme = (theme) => {
    if (theme === 'dark') {
      document.documentElement.classList.add('dark');
    } else {
      document.documentElement.classList.remove('dark');
    }
    localStorage.setItem('theme', theme);
  };
  
  // 初始化
  applyTheme(getTheme());
  
  // 切换函数
  window.toggleTheme = () => {
    const isDark = document.documentElement.classList.contains('dark');
    applyTheme(isDark ? 'light' : 'dark');
  };
})();

footer.php 中引入:

<script src="<?php $this->options->themeUrl('assets/js/theme.js'); ?>"></script>

6.3 暗黑模式切换按钮

<button onclick="toggleTheme()" 
        class="p-2 rounded-lg bg-gray-200 dark:bg-gray-700 
               text-gray-900 dark:text-gray-100
               hover:bg-gray-300 dark:hover:bg-gray-600
               transition-colors">
  <!-- 太阳/月亮图标 -->
  <svg class="w-5 h-5 dark:hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 
          d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
  </svg>
  <svg class="w-5 h-5 hidden dark:block" fill="none" stroke="currentColor" viewBox="0 0 24 24">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 
          d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
  </svg>
</button>

6.4 暗黑模式样式示例

/* 在 @layer components 中 */
@layer components {
  .card {
    @apply bg-white text-gray-900;
    @apply dark:bg-gray-800 dark:text-gray-100;
  }
  
  .nav-link {
    @apply text-gray-700 hover:text-primary;
    @apply dark:text-gray-300 dark:hover:text-primary-400;
  }
  
  .border-default {
    @apply border-gray-200;
    @apply dark:border-gray-700;
  }
}

七、与 project_rules.md 结合

7.1 迁移现有工具类

project_rules.md 中的工具类用 Tailwind 实现:

project_rules.md 类Tailwind 实现说明
.text-mutedtext-gray-500 dark:text-gray-400灰色文字
.text-successtext-green-600成功绿色
.text-dangertext-red-600危险红色
.text-centertext-center居中
.mt-1mt-1上边距 0.25rem
.mt-2mt-2上边距 0.5rem
.mt-3mt-3上边距 0.75rem
.d-flexflex弹性布局
.justify-betweenjustify-between两端对齐
.cardbg-white rounded-lg shadow p-4卡片容器

7.2 保留兼容层

style.css 中添加兼容类,确保旧代码也能工作:

/* 兼容 project_rules.md 旧类名 */
@layer utilities {
  .text-muted {
    @apply text-gray-500 dark:text-gray-400;
  }
  
  .text-success {
    @apply text-green-600;
  }
  
  .text-danger {
    @apply text-red-600;
  }
  
  .btn-sm {
    @apply px-3 py-1.5 text-sm;
  }
  
  .btn-lg {
    @apply px-6 py-3 text-lg;
  }
}

7.3 资源加载顺序

根据 project_rules.md 的要求:

<!-- header.php -->
<!-- 1. 基础样式 -->
<link rel="stylesheet" href="/tools/common/css/base.css">

<!-- 2. Tailwind 生成的样式 -->
<link rel="stylesheet" href="<?php $this->options->themeUrl('assets/css/style.min.css'); ?>">

<!-- 3. 主题私有样式(如有需要) -->
<link rel="stylesheet" href="<?php $this->options->themeUrl('style.css'); ?>">

八、常见问题

Q1: 为什么我添加的 Tailwind 类不起作用?

A: 检查以下几点:

  • tailwind.config.js 中的 content 配置是否正确包含你的 PHP 文件
  • 是否运行了 npm run buildnpm run dev
  • 是否正确引入了编译后的 CSS 文件

Q2: 如何添加自定义颜色?

A: 在 tailwind.config.jstheme.extend.colors 中添加:

module.exports = {
  theme: {
    extend: {
      colors: {
        brand: {
          light: '#3abff8',
          DEFAULT: '#0284c7',
          dark: '#0b5e8c',
        },
      },
    },
  },
}

使用:text-brandbg-brand-light

Q3: 如何使用任意值(如特殊宽度)?

A: 使用方括号语法:

<div class="w-[139px] h-[77px] bg-[#165DFF]">
  自定义尺寸和颜色
</div>

Q4: 如何复用重复的类组合?

A: 使用 @apply 在 CSS 中提取组件:

@layer components {
  .blog-card {
    @apply bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow;
  }
}

Q5: 生产环境 CSS 文件太大怎么办?

A: Tailwind 在生产模式 (npm run build) 会自动清除未使用的类。确保 content 配置正确即可。

Q6: 可以在插件中使用 Tailwind 吗?

A: 可以。两种方式:

  1. 独立编译:插件自带 Tailwind 配置,独立生成 CSS
  2. 共用主题:在主题的 tailwind.config.jscontent 中添加插件路径
content: [
  './**/*.php',
  '../../plugins/PluginName/**/*.php',  // 扫描插件
]

📝 总结

通过本教程,您已经掌握了:

  1. ✅ Tailwind CSS 的核心概念和优势
  2. ✅ 在 Typecho 主题中的完整安装配置流程
  3. ✅ 响应式设计和暗黑模式的实现方法
  4. ✅ 如何与现有的 project_rules.md 规范结合

推荐的开发流程

# 1. 进入主题目录
cd usr/themes/your-theme

# 2. 安装依赖(只需一次)
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

# 3. 开发时监听
npm run dev

# 4. 开发完成,编译生产版本
npm run build

已有 33 条评论

    1. 小雨 小雨

      照着教程把老主题重构了一遍,代码量少了三分之一。那些margin、padding不用再写自定义CSS了,直接utilities搞定。

    2. DavidK DavidK

      The warning about CDN being 3MB is important. Many beginners don't realize the size difference and wonder why their site is slow. Build process is worth the setup effort.

    3. 老周 老周

      之前用Tailwind写Vue项目很顺手,但一回到Typecho就不知道怎么配了。这篇完美解决了我的问题,现在前后端开发体验统一了。

    4. EmmaC EmmaC

      The darkMode: 'class' choice is correct. Media query dark mode is less flexible. Good to see best practices being taught.

    5. 行路者 行路者

      把这篇收藏了,以后每做一个Typecho主题就翻出来照着配一遍。tailwind.config.js里content的配置每次都记不住,这篇写得很清楚。