PostCSS 最佳实践 #

本文总结了 PostCSS 在实际项目中的最佳实践,帮助你更高效地使用 PostCSS。

项目配置 #

目录结构 #

text
project/
├── src/
│   ├── styles/
│   │   ├── base/
│   │   │   ├── _reset.css
│   │   │   └── _typography.css
│   │   ├── components/
│   │   │   ├── _buttons.css
│   │   │   └── _forms.css
│   │   ├── layout/
│   │   │   ├── _header.css
│   │   │   └── _footer.css
│   │   ├── utils/
│   │   │   ├── _variables.css
│   │   │   └── _mixins.css
│   │   └── main.css
│   └── ...
├── dist/
│   └── css/
│       └── main.css
├── postcss.config.js
├── .browserslistrc
└── package.json

推荐配置 #

开发环境 #

javascript
// postcss.config.js
module.exports = (ctx) => {
  const isDev = ctx.env !== 'production'
  
  return {
    plugins: [
      // 1. 导入处理
      require('postcss-import')({
        path: ['src/styles']
      }),
      
      // 2. 语法扩展
      require('postcss-nested'),
      require('postcss-simple-vars')({
        variables: require('./src/styles/utils/variables.json')
      }),
      
      // 3. 未来特性
      require('postcss-preset-env')({
        stage: 2,
        features: {
          'nesting-rules': true
        }
      }),
      
      // 4. 兼容性
      require('autoprefixer'),
      
      // 5. 开发工具
      isDev && require('postcss-reporter')({
        clearAllMessages: true
      })
    ].filter(Boolean)
  }
}

生产环境 #

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-nested'),
    require('postcss-simple-vars'),
    require('postcss-preset-env')({ stage: 2 }),
    require('autoprefixer'),
    require('cssnano')({
      preset: ['default', {
        discardComments: { removeAll: true },
        normalizeWhitespace: true,
        colormin: true,
        reduceIdents: false
      }]
    })
  ]
}

CSS 文件组织 #

css
/* main.css */

/* 1. 配置和变量 */
@import 'utils/variables.css';
@import 'utils/mixins.css';

/* 2. 基础样式 */
@import 'base/reset.css';
@import 'base/typography.css';

/* 3. 布局 */
@import 'layout/header.css';
@import 'layout/footer.css';
@import 'layout/sidebar.css';

/* 4. 组件 */
@import 'components/buttons.css';
@import 'components/forms.css';
@import 'components/cards.css';

/* 5. 页面特定样式 */
@import 'pages/home.css';
@import 'pages/about.css';

插件选择 #

核心插件 #

javascript
// 必备插件
const corePlugins = [
  'autoprefixer',      // 浏览器前缀
  'postcss-import',    // 导入处理
  'cssnano'            // 压缩优化
]

按需选择 #

javascript
// 根据项目需求选择
const optionalPlugins = {
  // 需要嵌套语法
  nesting: ['postcss-nested'],
  
  // 需要变量
  variables: ['postcss-simple-vars'],
  
  // 需要未来特性
  future: ['postcss-preset-env'],
  
  // 移动端适配
  mobile: ['postcss-pxtorem', 'postcss-px-to-viewport'],
  
  // RTL 支持
  rtl: ['rtlcss'],
  
  // 代码检查
  lint: ['stylelint']
}

避免重复功能 #

javascript
// ❌ 不推荐:同时使用多个预处理插件
module.exports = {
  plugins: [
    require('postcss-nested'),      // 嵌套
    require('postcss-nesting'),     // 另一个嵌套插件
    require('precss')               // 包含嵌套功能
  ]
}

// ✅ 推荐:选择一个
module.exports = {
  plugins: [
    require('postcss-nested')       // 只用一个
  ]
}

性能优化 #

插件顺序优化 #

javascript
// 正确的插件顺序
module.exports = {
  plugins: [
    // 1. 首先处理导入(减少文件数量)
    require('postcss-import'),
    
    // 2. 语法转换(增加代码量)
    require('postcss-nested'),
    require('postcss-simple-vars'),
    
    // 3. 兼容性处理(可能增加前缀)
    require('autoprefixer'),
    
    // 4. 最后压缩(减少代码量)
    require('cssnano')
  ]
}

使用缓存 #

javascript
// postcss.config.js
module.exports = {
  plugins: [
    // ...
  ],
  // 启用缓存
  map: {
    inline: false,
    annotation: true
  }
}

按需加载 #

javascript
// postcss.config.js
const isProduction = process.env.NODE_ENV === 'production'

module.exports = {
  plugins: [
    // 基础插件始终加载
    require('autoprefixer'),
    
    // 生产环境才压缩
    isProduction && require('cssnano')({
      preset: 'default'
    })
  ].filter(Boolean)
}

减少处理范围 #

javascript
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        exclude: /node_modules/,  // 排除 node_modules
        use: ['postcss-loader']
      }
    ]
  }
}

与构建工具集成 #

Webpack 最佳实践 #

javascript
// webpack.config.js
const isProduction = process.env.NODE_ENV === 'production'

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              sourceMap: !isProduction
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: !isProduction
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css'
    })
  ]
}

Vite 最佳实践 #

javascript
// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  css: {
    postcss: './postcss.config.js',
    devSourcemap: true
  },
  build: {
    cssMinify: true
  }
})

Gulp 最佳实践 #

javascript
// gulpfile.js
const gulp = require('gulp')
const postcss = require('gulp-postcss')
const sourcemaps = require('gulp-sourcemaps')
const gulpIf = require('gulp-if')

const isProduction = process.env.NODE_ENV === 'production'

gulp.task('css', () => {
  return gulp.src('src/styles/**/*.css')
    .pipe(gulpIf(!isProduction, sourcemaps.init()))
    .pipe(postcss())
    .pipe(gulpIf(!isProduction, sourcemaps.write('.')))
    .pipe(gulp.dest('dist/css'))
})

gulp.task('watch', () => {
  gulp.watch('src/styles/**/*.css', gulp.series('css'))
})

常见问题解决 #

问题 1:配置文件不生效 #

bash
# 检查配置文件位置
ls -la postcss.config.js

# 检查语法
node -e "console.log(require('./postcss.config.js'))"

# 清除缓存
rm -rf node_modules/.cache

问题 2:插件顺序错误 #

javascript
// ❌ 错误:cssnano 在前
module.exports = {
  plugins: [
    require('cssnano'),
    require('postcss-nested')
  ]
}

// ✅ 正确:cssnano 在后
module.exports = {
  plugins: [
    require('postcss-nested'),
    require('cssnano')
  ]
}

问题 3:Source Map 问题 #

javascript
// postcss.config.js
module.exports = {
  plugins: [
    // ...
  ],
  map: {
    inline: false,        // 不内联
    annotation: true,     // 添加注释
    sourcesContent: true  // 包含源内容
  }
}

问题 4:与 CSS 预处理器冲突 #

javascript
// 使用 Less/Sass 时,只使用兼容性插件
module.exports = {
  plugins: [
    require('autoprefixer'),
    require('postcss-preset-env')({
      stage: 2
    })
  ]
}

问题 5:浏览器兼容性问题 #

bash
# 更新 browserslist 数据
npx browserslist@latest --update-db

# 检查当前配置
npx browserslist

# 检查覆盖率
npx browserslist --coverage

代码风格 #

CSS 编写规范 #

css
/* 使用一致的命名 */
.component { }
.component__element { }
.component--modifier { }

/* 使用 CSS 变量 */
:root {
  --color-primary: #007bff;
  --spacing-base: 16px;
}

.button {
  color: var(--color-primary);
  padding: var(--spacing-base);
}

/* 使用嵌套保持结构清晰 */
.card {
  padding: 16px;
  
  &__header {
    font-size: 1.2em;
  }
  
  &__body {
    margin-top: 8px;
  }
  
  &:hover {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }
}

注释规范 #

css
/* ==========================================================================
   组件名称
   ========================================================================== */

/**
 * 简短描述
 * 
 * 长描述...
 * 
 * @example
 * <div class="button">Button</div>
 */

.button {
  /* 样式 */
}

/* TODO: 需要优化 */
/* FIXME: 需要修复 */
/* HACK: 临时解决方案 */
/* NOTE: 重要说明 */

调试技巧 #

开启详细日志 #

javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer'),
    require('postcss-reporter')({
      clearAllMessages: true,
      throwError: false
    })
  ]
}

使用调试插件 #

javascript
const debugPlugin = () => {
  return {
    postcssPlugin: 'debug',
    Once(root) {
      console.log('CSS Rules:', root.nodes.length)
    },
    Declaration(decl) {
      console.log(`${decl.prop}: ${decl.value}`)
    }
  }
}
debugPlugin.postcss = true

检查处理结果 #

javascript
const postcss = require('postcss')
const autoprefixer = require('autoprefixer')

async function debug(css) {
  const result = await postcss([autoprefixer])
    .process(css, { from: undefined })
  
  console.log('Input:', css)
  console.log('Output:', result.css)
  console.log('Warnings:', result.warnings())
  
  return result
}

安全考虑 #

避免注入攻击 #

javascript
// ❌ 不安全
const css = userInput

// ✅ 安全:验证输入
const css = validateUserInput(userInput)

限制导入路径 #

javascript
require('postcss-import')({
  // 限制导入路径
  path: ['src/styles'],
  // 过滤文件
  filter: path => !path.includes('..')
})

团队协作 #

共享配置 #

javascript
// 创建共享配置包
// @company/postcss-config/index.js
module.exports = {
  plugins: [
    require('autoprefixer'),
    require('cssnano')
  ]
}

// 项目中使用
// postcss.config.js
module.exports = require('@company/postcss-config')

文档化配置 #

javascript
// postcss.config.js

/**
 * PostCSS 配置文件
 * 
 * 插件说明:
 * - postcss-import: 处理 CSS 导入
 * - postcss-nested: 支持嵌套语法
 * - autoprefixer: 自动添加浏览器前缀
 * - cssnano: CSS 压缩优化
 * 
 * 浏览器支持:
 * - > 1% 全球使用率
 * - 最后 2 个版本
 * - 排除已停止维护的浏览器
 */
module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-nested'),
    require('autoprefixer'),
    require('cssnano')
  ]
}

持续集成 #

GitHub Actions #

yaml
# .github/workflows/css.yml
name: CSS Build

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      
      - run: npm ci
      
      - name: Build CSS
        run: npm run build:css
      
      - name: Check CSS
        run: npm run lint:css

Git Hooks #

json
// package.json
{
  "scripts": {
    "build:css": "postcss src/styles/main.css -o dist/css/main.css",
    "lint:css": "stylelint 'src/styles/**/*.css'"
  },
  "lint-staged": {
    "*.css": [
      "stylelint --fix",
      "postcss"
    ]
  }
}

监控与维护 #

定期更新 #

bash
# 更新 PostCSS 和插件
npm update postcss autoprefixer cssnano

# 检查过时的包
npm outdated

# 更新 browserslist 数据
npx browserslist@latest --update-db

性能监控 #

javascript
// 构建时间监控
const startTime = Date.now()

await postcss(plugins).process(css, { from: 'input.css' })

const duration = Date.now() - startTime
console.log(`Build time: ${duration}ms`)

总结 #

核心原则 #

  1. 按需选择插件:只使用项目需要的插件
  2. 正确的插件顺序:导入 → 转换 → 兼容 → 压缩
  3. 配置文件管理:使用独立的配置文件
  4. 性能优化:缓存、按需加载、减少处理范围
  5. 团队协作:共享配置、文档化

检查清单 #

  • [ ] 配置文件正确放置
  • [ ] 插件顺序正确
  • [ ] 浏览器兼容性配置
  • [ ] 开发/生产环境区分
  • [ ] Source Map 配置
  • [ ] 构建工具集成
  • [ ] 代码风格统一
  • [ ] 持续集成配置
  • [ ] 定期更新依赖

恭喜你完成了 PostCSS 完全指南的学习!现在你已经掌握了从基础到进阶的 PostCSS 知识,可以在项目中高效地使用 PostCSS 了。

最后更新:2026-03-28