Lightning CSSで高速CSSビルドパイプラインを構築


はじめに

Lightning CSSは、Parcelチームが開発したRust製の高速CSSパーサー・トランスフォーマー・ミニファイアである。旧名「Parcel CSS」として知られていたが、2022年にスタンドアロンツールとしてリブランドされた。PostCSS + autoprefixer + cssnanoの組み合わせと比較して、数十倍から百倍以上のパフォーマンスを実現する。

2026年現在、Lightning CSSはVite・Astro・Next.jsなど主要なビルドツールで採用が進み、CSSビルドパイプラインの事実上の標準になりつつある。本記事では、Lightning CSSの導入方法から実践的な設定、既存のPostCSS環境からの移行方法までを体系的に解説する。

対象読者

  • CSSビルドパイプラインの最適化に関心のあるフロントエンドエンジニア
  • PostCSSからの移行を検討しているプロジェクトの技術リーダー
  • CSS ModulesやネスティングなどモダンCSS機能を活用したい開発者

Lightning CSSとは何か

Lightning CSSは以下の機能を1つのツールで提供する。

機能説明PostCSS相当
パースCSSの構文解析postcss本体
ベンダープレフィックス自動付与・除去autoprefixer
構文変換ネスティング、カスタムメディアクエリ等postcss-nesting, postcss-custom-media
CSS Modulesクラス名のスコープ化postcss-modules
ミニファイ圧縮・最適化cssnano
バンドリング@importの解決・結合postcss-import
ブラウザターゲット対象ブラウザに応じた変換browserslist + autoprefixer

これらすべてがRustで実装されており、JavaScriptベースのPostCSSプラグインチェーンと比較して桁違いのパフォーマンスを発揮する。

パフォーマンスベンチマーク

以下は100KBのCSSファイルを処理した場合の比較データである(Lightning CSS公式ベンチマークおよびコミュニティ計測を基にした参考値)。

ツールチェーン処理時間倍率
PostCSS + autoprefixer + cssnano~500ms1x(基準)
esbuild CSS~15ms約33x
Lightning CSS~5ms約100x

この差は、ファイル数が増えるほど顕著になる。数百ファイルのCSS Modulesを持つ大規模プロジェクトでは、ビルド時間が数十秒から数百ミリ秒に短縮されることもある。

インストールと基本的な使い方

npmパッケージのインストール

# プロジェクトへのインストール
npm install lightningcss lightningcss-cli --save-dev

# グローバルインストール(CLI利用のみ)
npm install -g lightningcss-cli

CLI基本操作

最も基本的な使い方はCLIからのファイル変換である。

# 基本的な変換
npx lightningcss --minify --bundle input.css -o output.css

# ブラウザターゲットを指定して変換
npx lightningcss --minify --bundle \
  --targets '>= 0.25%' \
  input.css -o output.css

# CSS Modulesとして処理
npx lightningcss --minify --bundle \
  --css-modules \
  input.css -o output.css

# ソースマップ付き
npx lightningcss --minify --bundle \
  --source-map \
  input.css -o output.css

Node.js APIでの利用

プログラマティックに使用する場合は、Node.js APIを利用する。

import { transform, bundle } from 'lightningcss';
import { readFileSync } from 'fs';

// 単一ファイルの変換
const result = transform({
  filename: 'style.css',
  code: readFileSync('style.css'),
  minify: true,
  targets: {
    chrome: (110 << 16),   // Chrome 110
    firefox: (115 << 16),  // Firefox 115
    safari: (16 << 16) | (4 << 8),  // Safari 16.4
  },
  drafts: {
    customMedia: true,
  },
});

console.log(result.code.toString());

// バンドル(@importの解決含む)
const bundled = bundle({
  filename: 'src/styles/main.css',
  minify: true,
  targets: {
    chrome: (110 << 16),
    firefox: (115 << 16),
    safari: (16 << 16) | (4 << 8),
  },
});

console.log(bundled.code.toString());

targetsのバージョンはビット演算で指定する。(major << 16) | (minor << 8) | patchという形式で、Chrome 110は110 << 16、Safari 16.4は(16 << 16) | (4 << 8)となる。

ブラウザターゲット設定

Lightning CSSの最大の特徴の1つが、ブラウザターゲットに基づく自動変換である。ターゲットブラウザが対応していないCSS機能は、自動的にフォールバックコードに変換される。

ターゲット指定方法

// Node.js APIでの指定
const targets = {
  chrome: (110 << 16),
  firefox: (115 << 16),
  safari: (16 << 16) | (4 << 8),
  edge: (110 << 16),
  ios_saf: (16 << 16) | (4 << 8),
  android: (110 << 16),
};

CLIではbrowserslistクエリを直接使用できる。

npx lightningcss --targets '>= 0.25%' input.css -o output.css
npx lightningcss --targets 'last 2 versions' input.css -o output.css
npx lightningcss --targets 'defaults' input.css -o output.css

自動変換の例

入力CSS(モダン構文)を書くと、ターゲットに応じてLightning CSSが自動変換する。

入力:

/* oklch色空間 */
.card {
  background-color: oklch(0.7 0.15 200);
  color: oklch(0.3 0.05 200);
}

/* color-mix関数 */
.hover-card {
  background-color: color-mix(in oklch, var(--primary) 80%, white);
}

/* CSSネスティング */
.nav {
  display: flex;
  gap: 1rem;

  & a {
    color: inherit;
    text-decoration: none;

    &:hover {
      text-decoration: underline;
    }
  }

  & .active {
    font-weight: bold;
  }
}

古いブラウザをターゲットに含めた場合の出力:

.card {
  background-color: #1a9caa;
  background-color: oklch(.7 .15 200);
  color: #2d4a4e;
  color: oklch(.3 .05 200);
}

.nav {
  display: flex;
  gap: 1rem;
}

.nav a {
  color: inherit;
  text-decoration: none;
}

.nav a:hover {
  text-decoration: underline;
}

.nav .active {
  font-weight: bold;
}

oklch非対応ブラウザに対してRGBフォールバックが自動生成され、ネスティングは展開される。対応ブラウザのみをターゲットにしている場合は、元のコードがそのまま出力される。

CSS Modules対応

Lightning CSSはCSS Modulesをネイティブサポートしている。PostCSS + postcss-modulesの組み合わせと比較して、設定が簡潔で処理速度も大幅に向上する。

基本的なCSS Modules

/* components/Button.module.css */
.root {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 1rem;
  border-radius: 0.375rem;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.2s, box-shadow 0.2s;
}

.primary {
  composes: root;
  background-color: var(--color-primary);
  color: white;
}

.primary:hover {
  background-color: var(--color-primary-dark);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.secondary {
  composes: root;
  background-color: transparent;
  color: var(--color-primary);
  border: 1px solid var(--color-primary);
}

.icon {
  margin-right: 0.5rem;
  width: 1.25rem;
  height: 1.25rem;
}

.disabled {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

Node.js APIでCSS Modulesを処理

import { bundle } from 'lightningcss';

const result = bundle({
  filename: 'components/Button.module.css',
  minify: true,
  cssModules: true,
  targets: {
    chrome: (110 << 16),
  },
});

// 変換後のCSS
console.log(result.code.toString());

// クラス名のマッピング
// { root: { name: 'Button_root_a1b2c3', composes: [] }, ... }
console.log(result.exports);

CSS Modulesの設定オプション

const result = bundle({
  filename: 'style.module.css',
  cssModules: {
    // クラス名のパターン
    pattern: '[name]_[local]_[hash]',
    // ハッシュのアルゴリズムをカスタマイズ可能
    // dashedIdents: true にするとCSS変数もスコープ化
    dashedIdents: true,
  },
  minify: true,
});

dashedIdents: trueを設定すると、--color-primaryのようなCSS Custom Propertiesもモジュールスコープに含まれる。コンポーネント間のスタイル干渉を完全に防ぐことができる。

CSSネスティングとモダン構文サポート

Lightning CSSは最新のCSS仕様をネイティブにサポートする。ターゲットブラウザに応じて自動的にフォールバックコードを生成するため、開発時は最新の構文で記述できる。

ネスティング

/* モダンなCSS Nesting */
.card {
  padding: 1.5rem;
  border-radius: 0.75rem;
  background: white;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);

  & .header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1rem;

    & h3 {
      font-size: 1.125rem;
      font-weight: 600;
      margin: 0;
    }

    & .badge {
      font-size: 0.75rem;
      padding: 0.125rem 0.5rem;
      border-radius: 9999px;
      background: oklch(0.9 0.05 200);
    }
  }

  & .body {
    line-height: 1.6;
    color: oklch(0.4 0.02 250);
  }

  & .footer {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid oklch(0.9 0 0);
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
  }

  /* メディアクエリのネスティング */
  @media (max-width: 640px) {
    padding: 1rem;

    & .header {
      flex-direction: column;
      align-items: flex-start;
    }
  }
}

カスタムメディアクエリ

/* カスタムメディアクエリの定義 */
@custom-media --mobile (max-width: 640px);
@custom-media --tablet (min-width: 641px) and (max-width: 1024px);
@custom-media --desktop (min-width: 1025px);
@custom-media --dark-mode (prefers-color-scheme: dark);
@custom-media --reduced-motion (prefers-reduced-motion: reduce);

.layout {
  display: grid;
  gap: 1.5rem;

  @media (--mobile) {
    grid-template-columns: 1fr;
  }

  @media (--tablet) {
    grid-template-columns: repeat(2, 1fr);
  }

  @media (--desktop) {
    grid-template-columns: repeat(3, 1fr);
  }
}

.animation-element {
  transition: transform 0.3s ease;

  @media (--reduced-motion) {
    transition: none;
  }
}

カスタムメディアクエリを使用するには、drafts.customMediaを有効にする必要がある。

const result = transform({
  filename: 'style.css',
  code: Buffer.from(css),
  drafts: {
    customMedia: true,
  },
});

カラー関数

Lightning CSSはモダンなCSS Color Level 4/5の関数をサポートする。

:root {
  /* oklch色空間でデザイントークンを定義 */
  --primary-hue: 250;
  --primary: oklch(0.55 0.2 var(--primary-hue));
  --primary-light: oklch(0.75 0.15 var(--primary-hue));
  --primary-dark: oklch(0.35 0.2 var(--primary-hue));

  /* P3広色域 */
  --accent: color(display-p3 0.2 0.8 0.4);

  /* color-mix */
  --primary-hover: color-mix(in oklch, var(--primary) 85%, black);
  --primary-subtle: color-mix(in oklch, var(--primary) 10%, white);
}

/* ライト/ダーク自動切替 */
.surface {
  background: light-dark(white, oklch(0.2 0.02 250));
  color: light-dark(oklch(0.2 0.02 250), oklch(0.9 0.02 250));
}

Viteとの連携

ViteはLightning CSSをビルトインでサポートしている。設定は非常にシンプルである。

Vite設定

// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  css: {
    transformer: 'lightningcss',
    lightningcss: {
      // ブラウザターゲット
      targets: {
        chrome: (110 << 16),
        firefox: (115 << 16),
        safari: (16 << 16) | (4 << 8),
      },
      // CSS Modulesの設定
      cssModules: {
        pattern: '[name]_[local]_[hash]',
        dashedIdents: true,
      },
      // ドラフト機能
      drafts: {
        customMedia: true,
      },
    },
  },
  build: {
    cssMinify: 'lightningcss',
  },
});

browserslistとの連携

browserslist設定を直接使用する場合は、browserslistパッケージとlightningcssのヘルパーを組み合わせる。

// vite.config.js
import { defineConfig } from 'vite';
import browserslist from 'browserslist';
import { browserslistToTargets } from 'lightningcss';

const targets = browserslistToTargets(
  browserslist('defaults')
);

export default defineConfig({
  css: {
    transformer: 'lightningcss',
    lightningcss: {
      targets,
    },
  },
  build: {
    cssMinify: 'lightningcss',
  },
});

ReactコンポーネントでのCSS Modules利用

// components/Card.jsx
import styles from './Card.module.css';

export function Card({ title, children, variant = 'default' }) {
  const cardClass = [
    styles.card,
    variant === 'elevated' && styles.elevated,
    variant === 'outlined' && styles.outlined,
  ].filter(Boolean).join(' ');

  return (
    <div className={cardClass}>
      <h3 className={styles.title}>{title}</h3>
      <div className={styles.content}>{children}</div>
    </div>
  );
}
/* components/Card.module.css */
.card {
  padding: 1.5rem;
  border-radius: 0.75rem;
  background: var(--surface);
  transition: box-shadow 0.2s ease, transform 0.2s ease;

  &:hover {
    transform: translateY(-2px);
  }
}

.elevated {
  composes: card;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
              0 2px 4px -2px rgba(0, 0, 0, 0.1);

  &:hover {
    box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
                0 4px 6px -4px rgba(0, 0, 0, 0.1);
  }
}

.outlined {
  composes: card;
  border: 1px solid var(--border-color);
  box-shadow: none;
}

.title {
  font-size: 1.125rem;
  font-weight: 600;
  margin: 0 0 0.75rem;
  line-height: 1.4;
}

.content {
  color: var(--text-secondary);
  line-height: 1.6;
}

Webpack連携

既存のWebpackプロジェクトでLightning CSSを使用する場合は、専用のloaderを導入する。

設定例

npm install lightningcss lightningcss-loader --save-dev
// webpack.config.js
const browserslist = require('browserslist');
const { browserslistToTargets } = require('lightningcss');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
            },
          },
          {
            loader: 'lightningcss-loader',
            options: {
              targets: browserslistToTargets(
                browserslist('defaults')
              ),
              drafts: {
                customMedia: true,
              },
            },
          },
        ],
      },
      // CSS Modules用の設定
      {
        test: /\.module\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              modules: true,
            },
          },
          {
            loader: 'lightningcss-loader',
            options: {
              targets: browserslistToTargets(
                browserslist('defaults')
              ),
              cssModules: true,
            },
          },
        ],
      },
    ],
  },
};

PostCSSからの移行ガイド

既存のPostCSS環境からLightning CSSへの移行は段階的に行うことを推奨する。

移行チェックリスト

PostCSSプラグインLightning CSS対応移行方法
autoprefixer組み込みtargets設定で自動対応
postcss-nesting組み込み変更不要(CSS標準構文で記述)
postcss-custom-media組み込みdrafts.customMedia: true
cssnano組み込みminify: true
postcss-import組み込み(bundle使用時)bundle()関数を使用
postcss-modules組み込みcssModules: true
postcss-preset-env部分対応個別機能ごとに確認が必要
postcss-mixins非対応CSS標準機能で代替
tailwindcss非対応PostCSSと併用が必要

移行手順

Step 1: 並行稼働

まずLightning CSSを追加インストールし、PostCSSと並行して動作確認する。

npm install lightningcss --save-dev

Step 2: 互換性確認スクリプトの作成

// scripts/check-css-compat.mjs
import { transform } from 'lightningcss';
import { readFileSync, readdirSync } from 'fs';
import { join, extname } from 'path';

function checkFile(filePath) {
  try {
    const code = readFileSync(filePath);
    const result = transform({
      filename: filePath,
      code,
      minify: false,
      targets: {
        chrome: (110 << 16),
        firefox: (115 << 16),
        safari: (16 << 16) | (4 << 8),
      },
    });
    console.log(`OK: ${filePath}`);
    return true;
  } catch (error) {
    console.error(`NG: ${filePath}`);
    console.error(`   ${error.message}`);
    return false;
  }
}

function scanDirectory(dir) {
  const files = readdirSync(dir, { withFileTypes: true });
  let okCount = 0;
  let ngCount = 0;

  for (const file of files) {
    const fullPath = join(dir, file.name);
    if (file.isDirectory()) {
      const result = scanDirectory(fullPath);
      okCount += result.ok;
      ngCount += result.ng;
    } else if (extname(file.name) === '.css') {
      if (checkFile(fullPath)) {
        okCount++;
      } else {
        ngCount++;
      }
    }
  }

  return { ok: okCount, ng: ngCount };
}

const result = scanDirectory('src');
console.log(`\n合計: ${result.ok} OK, ${result.ng} NG`);

Step 3: PostCSS設定の削除

互換性確認が完了したら、PostCSS関連パッケージを削除する。

npm uninstall postcss autoprefixer cssnano postcss-nesting postcss-import postcss-custom-media
rm postcss.config.js

Step 4: ビルドツール設定の更新

Viteの場合はcss.transformer: 'lightningcss'を設定するだけで移行完了である。

注意点: Tailwind CSSとの併用

Tailwind CSSはPostCSSプラグインとして動作するため、Lightning CSSに完全移行はできない。ただし、以下の構成でミニファイとベンダープレフィックスのみLightning CSSに担当させることは可能である。

// vite.config.js - Tailwind CSS + Lightning CSS併用
export default defineConfig({
  css: {
    // PostCSSでTailwindを処理
    postcss: {
      plugins: [
        tailwindcss(),
        // autoprefixerは不要(Lightning CSSが処理)
      ],
    },
  },
  build: {
    // ミニファイのみLightning CSS
    cssMinify: 'lightningcss',
  },
});

パフォーマンス最適化のベストプラクティス

バンドルサイズの最小化

import { bundle } from 'lightningcss';

const result = bundle({
  filename: 'src/styles/main.css',
  minify: true,
  targets: {
    chrome: (110 << 16),
    firefox: (115 << 16),
    safari: (16 << 16) | (4 << 8),
  },
  // 未使用のCSSを除去しない(Lightning CSS単体では不可)
  // → PurgeCSSやTailwindのpurge機能と組み合わせる
});

// 出力サイズの確認
const outputSize = result.code.length;
const gzipSize = Buffer.byteLength(
  require('zlib').gzipSync(result.code)
);
console.log(`出力: ${outputSize} bytes`);
console.log(`gzip: ${gzipSize} bytes`);

ソースマップの活用

開発時はソースマップを有効にし、本番ビルドでは無効にする。

const isDev = process.env.NODE_ENV !== 'production';

const result = transform({
  filename: 'style.css',
  code: readFileSync('style.css'),
  minify: !isDev,
  sourceMap: isDev,
  targets: {
    chrome: (110 << 16),
  },
});

if (isDev && result.map) {
  // ソースマップを別ファイルに出力
  writeFileSync('output.css.map', result.map);
}

キャッシュ戦略

Lightning CSSは処理が高速であるため、キャッシュの必要性はPostCSSほど高くない。しかし、CI/CD環境では以下のように出力ハッシュを利用したキャッシュバスティングが有効である。

import { createHash } from 'crypto';

const result = bundle({
  filename: 'src/styles/main.css',
  minify: true,
});

const hash = createHash('md5')
  .update(result.code)
  .digest('hex')
  .slice(0, 8);

writeFileSync(`dist/styles.${hash}.css`, result.code);

Astro連携

AstroはLightning CSSをビルトインでサポートしている。

// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  vite: {
    css: {
      transformer: 'lightningcss',
      lightningcss: {
        targets: {
          chrome: (110 << 16),
          firefox: (115 << 16),
          safari: (16 << 16) | (4 << 8),
        },
        drafts: {
          customMedia: true,
        },
      },
    },
    build: {
      cssMinify: 'lightningcss',
    },
  },
});

関連記事

まとめ

Lightning CSSは、CSSビルドパイプラインにおけるパフォーマンスとシンプルさの両方を実現するツールである。本記事の内容を整理する。

項目ポイント
パフォーマンスPostCSS比で約100倍高速
統合性パース・プレフィックス・ミニファイ・バンドルを1ツールで
ブラウザターゲット指定ブラウザに応じた自動フォールバック生成
CSS Modulesネイティブサポート、dashedIdentsでCSS変数もスコープ化
モダンCSSネスティング、oklch、color-mix、カスタムメディアクエリ
Vite連携css.transformer: 'lightningcss'で設定完了
PostCSS移行段階的移行可能。Tailwind CSSとの併用も可

フロントエンド開発のビルド時間短縮は、開発者体験(DX)に直結する。特に大規模プロジェクトでは、Lightning CSSの導入効果は絶大である。PostCSSから段階的に移行を進め、モダンCSSの恩恵を最大限に活用することを推奨する。