PostCSS の使い方完全ガイド — JSプラグインでCSSを自在に変換するツール
一言でいうと
PostCSS は、JavaScript プラグインを通じて CSS を解析・変換するためのツールです。CSS をAST(抽象構文木)にパースし、プラグインが自由に操作できる基盤を提供することで、Autoprefixer によるベンダープレフィックス付与、Stylelint によるリント、将来の CSS 構文のトランスパイルなど、多彩な CSS 処理を実現します。
どんな時に使う?
- ベンダープレフィックスの自動付与 — Autoprefixer プラグインと組み合わせて、
display: flexなどに必要なプレフィックスを自動で追加したい場合 - CSS のリント・品質チェック — Stylelint と連携して、コーディング規約の遵守やバグの検出を行いたい場合
- 次世代 CSS 構文のトランスパイル —
postcss-preset-envを使い、ネスティングやカスタムメディアクエリなど、まだブラウザサポートが不十分な CSS 機能を現在のブラウザで動くコードに変換したい場合 - CSS Modules やスコープ付き CSS の実現 —
postcss-modulesなどを使い、クラス名の衝突を防ぐ仕組みを導入したい場合 - 独自の CSS 変換処理の構築 — 自作プラグインを書いて、プロジェクト固有の CSS 変換ロジックを実装したい場合
インストール
# npm
npm install postcss
# yarn
yarn add postcss
# pnpm
pnpm add postcss
多くの場合、PostCSS 単体ではなくプラグインと一緒にインストールします。
# よくある組み合わせ例
npm install postcss autoprefixer postcss-preset-env
CLI で使いたい場合は postcss-cli も追加します。
npm install postcss postcss-cli
基本的な使い方
PostCSS の最も基本的な使い方は、CSS 文字列を読み込み → プラグインで変換 → 結果を出力 という流れです。
import postcss from 'postcss';
import autoprefixer from 'autoprefixer';
const inputCss = `
.container {
display: flex;
user-select: none;
transition: transform 0.3s;
}
`;
async function processCss(): Promise<void> {
const result = await postcss([autoprefixer]).process(inputCss, {
from: undefined, // 入力ファイルパス(文字列直接の場合は undefined)
to: undefined, // 出力ファイルパス
});
console.log(result.css);
// ベンダープレフィックスが付与された CSS が出力される
// 警告があれば表示
for (const warning of result.warnings()) {
console.warn(warning.toString());
}
}
processCss();
ファイルを読み書きする実践的なパターン
import postcss from 'postcss';
import autoprefixer from 'autoprefixer';
import postcssPresetEnv from 'postcss-preset-env';
import { readFile, writeFile } from 'node:fs/promises';
async function buildCss(): Promise<void> {
const inputCss = await readFile('src/styles/main.css', 'utf-8');
const result = await postcss([
postcssPresetEnv({ stage: 2 }),
autoprefixer,
]).process(inputCss, {
from: 'src/styles/main.css',
to: 'dist/styles/main.css',
map: { inline: false }, // 外部ソースマップを生成
});
await writeFile('dist/styles/main.css', result.css);
if (result.map) {
await writeFile('dist/styles/main.css.map', result.map.toString());
}
}
buildCss();
postcss.config.js を使った設定
多くのビルドツール(webpack、Vite、Next.js など)は postcss.config.js を自動で読み込みます。
// postcss.config.js
module.exports = {
plugins: [
require('postcss-preset-env')({ stage: 2 }),
require('autoprefixer'),
],
};
よく使う API
1. postcss(plugins).process() — CSS の変換処理
最も頻繁に使うエントリーポイントです。
import postcss, { type Result } from 'postcss';
import autoprefixer from 'autoprefixer';
const result: Result = await postcss([autoprefixer]).process(
'a { color: red }',
{ from: 'input.css', to: 'output.css' }
);
console.log(result.css); // 変換後の CSS 文字列
console.log(result.map); // ソースマップ(設定時)
console.log(result.warnings()); // 警告の配列
2. postcss.parse() — CSS を AST にパース
CSS 文字列を直接 AST(Root ノード)に変換します。プラグインを通さず AST を操作したい場合に使います。
import postcss, { type Root } from 'postcss';
const root: Root = postcss.parse(`
.header {
color: blue;
font-size: 16px;
}
.footer {
color: gray;
}
`);
// すべてのルールを走査
root.walkRules((rule) => {
console.log(`セレクタ: ${rule.selector}`);
});
// すべての宣言(プロパティ)を走査
root.walkDecls((decl) => {
console.log(`${decl.prop}: ${decl.value}`);
});
3. root.walk*() 系メソッド — AST の走査
AST を効率的に走査するためのメソッド群です。
import postcss from 'postcss';
const root = postcss.parse(`
@media (max-width: 768px) {
.container {
color: red;
background: url('image.png');
}
}
/* コメント */
`);
// すべてのノードを走査
root.walk((node) => {
console.log(node.type); // 'atrule' | 'rule' | 'decl' | 'comment'
});
// @ルールのみ走査
root.walkAtRules('media', (atRule) => {
console.log(atRule.params); // '(max-width: 768px)'
});
// 特定プロパティの宣言のみ走査
root.walkDecls('color', (decl) => {
decl.value = 'blue'; // color の値をすべて blue に変更
});
// コメントのみ走査
root.walkComments((comment) => {
comment.remove(); // コメントをすべて削除
});
4. カスタムプラグインの作成
PostCSS プラグインは決まった形式の関数です。
import postcss, { type PluginCreator } from 'postcss';
interface RemoveCommentsOptions {
preserveImportant?: boolean;
}
const removeComments: PluginCreator<RemoveCommentsOptions> = (
opts = {}
) => {
const { preserveImportant = true } = opts;
return {
postcssPlugin: 'postcss-remove-comments',
Comment(comment) {
if (preserveImportant && comment.text.startsWith('!')) {
return; // 「!」で始まるコメントは残す
}
comment.remove();
},
};
};
removeComments.postcss = true;
// 使用例
async function run(): Promise<void> {
const input = `
/* 通常のコメント */
/*! 重要なコメント */
.foo { color: red; }
`;
const result = await postcss([
removeComments({ preserveImportant: true }),
]).process(input, { from: undefined });
console.log(result.css);
// /*! 重要なコメント */
// .foo { color: red; }
}
run();
5. AST ノードの生成・操作
プログラム的に CSS を組み立てたり変更したりできます。
import postcss from 'postcss';
// 新しい Root を作成
const root = postcss.parse('');
// ルールを追加
const rule = postcss.rule({ selector: '.button' });
rule.append(postcss.decl({ prop: 'display', value: 'inline-flex' }));
rule.append(postcss.decl({ prop: 'padding', value: '8px 16px' }));
rule.append(postcss.decl({ prop: 'border-radius', value: '4px' }));
root.append(rule);
// @media ルールを追加
const media = postcss.atRule({
name: 'media',
params: '(max-width: 768px)',
});
const mobileRule = postcss.rule({ selector: '.button' });
mobileRule.append(postcss.decl({ prop: 'width', value: '100%' }));
media.append(mobileRule);
root.append(media);
console.log(root.toString());
// .button {
// display: inline-flex;
// padding: 8px 16px;
// border-radius: 4px
// }
// @media (max-width: 768px) {
// .button {
// width: 100%
// }
// }
類似パッケージとの比較
| 特徴 | PostCSS | Sass (dart-sass) | Less | Lightning CSS |
|---|---|---|---|---|
| アプローチ | プラグインベースの CSS 変換基盤 | 独自構文のプリプロセッサ | 独自構文のプリプロセッサ | Rust 製の高速 CSS パーサー/変換 |
| 拡張性 | ◎ プラグインで自由に拡張 | △ 関数・ミックスインで拡張 | △ 関数・ミックスインで拡張 | △ 組み込み機能のみ |
| 速度 | ○ JS ベース | ○ Dart VM | ○ JS ベース | ◎ Rust ネイティブで非常に高速 |
| エコシステム | ◎ 数百のプラグイン | ◎ 長い歴史と豊富な資産 | ○ 成熟しているが縮小傾向 | △ 新しく成長中 |
| 標準 CSS との互換性 | ◎ 標準 CSS をそのまま扱える | △ 独自構文 | △ 独自構文 | ◎ 標準 CSS ベース |
| ソースマップ | ◎ | ◎ | ◎ | ◎ |
| 主な用途 | Autoprefixer、リント、将来構文変換 | 変数・ネスト・ミックスイン | 変数・ネスト・ミックスイン | ミニファイ、プレフィックス、バンドル |
補足: PostCSS と Sass/Less は競合ではなく併用されることが多いです。Sass でプリプロセスした後に PostCSS で Autoprefixer を適用する、というのは非常に一般的なワークフローです。Lightning CSS は PostCSS の一部ユースケース(Autoprefixer、ミニファイなど)を高速に代替できますが、プラグインエコシステムの柔軟性では PostCSS に及びません。
注意点・Tips
1. from オプションは必ず指定する
from を省略するとソースマップが正しく生成されず、警告が出ます。文字列を直接処理する場合は明示的に from: undefined を渡しましょう。
// ❌ 警告が出る
await postcss([plugin]).process(css);
// ✅ 明示的に undefined を指定
await postcss([plugin]).process(css, { from: undefined });
// ✅ ファイルパスがあるなら指定
await postcss([plugin]).process(css, { from: 'src/style.css' });
2. 同期 API と非同期 API
PostCSS v8 では .process() は LazyResult を返します。非同期プラグインを使う場合は必ず await してください。
// 非同期(推奨)
const result = await postcss([plugin]).process(css, { from: undefined });
// 同期的にアクセスしたい場合(非同期プラグインがないことが前提)
const lazyResult = postcss([plugin]).process(css, { from: undefined });
const syncCss = lazyResult.css; // 同期プラグインのみなら動作する
3. プラグインの順序は重要
プラグインは配列の先頭から順に実行されます。順序を間違えると意図しない結果になります。
// ✅ 推奨順序: 構文変換 → プレフィックス → ミニファイ
postcss([
postcssPresetEnv({ stage: 2 }), // 1. 将来構文を変換
autoprefixer, // 2. ベンダープレフィックスを付与
cssnano, // 3. 最後にミニファイ
]);
4. PostCSS v8 のプラグイン互換性
PostCSS v8 ではプラグイン API が変更されました。古いプラグイン(v7 以前向け)を使うと互換性の警告が出ることがあります。プラグインの peerDependencies を確認し、PostCSS v8 対応版を使いましょう。