メインコンテンツへスキップ
ブログ一覧に戻る
Web制作・運用

JavaScript/CSS最適化完全ガイド:パフォーマンスを劇的に改善する実践手法

2025年11月17日
11分で読めます
JavaScript/CSS最適化完全ガイド:パフォーマンスを劇的に改善する実践手法

この記事の結論

JavaScript/CSS最適化の基礎から実践まで完全解説。コード分割、ミニファイ、Tree Shaking、バンドル最適化、Critical CSSの実装方法を、具体的なコード例とベストプラクティスを交えて詳しく説明します。

JavaScript/CSS最適化完全ガイド:パフォーマンスを劇的に改善する実践手法

「JavaScriptが重くて読み込みが遅い」「FIDが改善しない」「バンドルサイズが大きすぎる」と感じたことはありませんか?

この記事が想定する読者:Web制作・開発の現場で、技術選定や改善の判断軸を持ちたい方。情報収集で止まらず、前提・優先順位・次の一手まで整理したい担当者。

判断を誤るとどうなるか:一般論の理解だけで終えると、自社の制約(スタック・工数・運用体制)とずれて選定や実装が空回りしやすい。前提・撤退線・次の一手まで言語化してから進めると判断がぶれにくくなります。

JavaScript/CSS最適化は、Webサイトのパフォーマンスを改善する重要な方法です。JavaScriptとCSSは、ページの読み込み時間、FID(First Input Delay)、TBT(Total Blocking Time)に直接影響します。

この記事では、JavaScript/CSS最適化の基礎から実践まで、コード分割、ミニファイ、Tree Shaking、バンドル最適化、Critical CSSの実装方法を、具体的なコード例とベストプラクティスを交えて網羅的に解説します。

この記事を読む前に

この記事では、Webサイト制作とパフォーマンスの基礎知識があることを前提としています。以下の記事を事前に読んでおくと、より深く理解できます:

この記事でわかること

  • JavaScript/CSS最適化とは何か、なぜ重要なのか
  • コード分割の実装方法
  • ミニファイと圧縮の最適化
  • Tree Shakingの活用
  • バンドルサイズの最適化
  • Critical CSSの実装
  • 非同期読み込みの最適化
  • 具体的な最適化事例

1. JavaScript/CSS最適化とは何か?

1.1 基本的な定義

JavaScript/CSS最適化とは、JavaScriptとCSSファイルのサイズを削減し、読み込み速度と実行速度を向上させるプロセスです。

JavaScript/CSS最適化が重要な理由

JavaScriptとCSSは、ページのパフォーマンスに直接影響します。ファイルサイズが大きいと、読み込み時間が長くなります。例えば、500KBのJavaScriptファイルを100KBに削減することで、読み込み時間を80%短縮できます。JavaScriptの実行が長いと、FID(First Input Delay)が悪化します。例えば、メインスレッドをブロックする処理を削減することで、FIDを改善できます。メインスレッドのブロック時間が長いと、TBT(Total Blocking Time)が悪化します。CSSの読み込みが遅いと、LCP(Largest Contentful Paint)が悪化します。例えば、クリティカルCSSをインライン化することで、LCPを改善できます。

1.2 最適化の種類

コード分割

  • コードを小さなチャンクに分割
  • 必要なコードだけを読み込む

ミニファイと圧縮

  • コードを最小化
  • Gzip/Brotli圧縮

Tree Shaking

  • 使用されていないコードを削除

バンドル最適化

  • バンドルサイズを最適化
  • 重複コードの削除

各手法の判断ポイント

手法主に効く指標目安の効果先に決めておくこと
コード分割初期 JS 量、FID初期 JS を 20–80% 削減しやすいどの画面を「初期必須」とするかの線引き
ミニファイと圧縮転送量、LCP合計 50–70% 減ることが多いCDN/サーバー側の Brotli/Gzip 対応状況
Tree Shakingバンドルサイズライブラリ依存度で差が大きいimport の書き方

判断ポイント:3 つを同時に全部やるより、「どの指標が最も詰まっているか」を先に特定する。詰まっている箇所に効く手段から入れるほうが、効果と工数のバランスが取りやすい。

2. コード分割

2.1 動的インポート

基本的な実装

// ❌ 悪い例:全てのコードを一度に読み込む
import HeavyComponent from './HeavyComponent';

// ✅ 良い例:動的インポート
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <p>Loading...</p>,
});

動的インポートにより、必要なコードだけを読み込むことができます。これにより、初期読み込み時のJavaScriptの量を削減し、パフォーマンスを向上させます。例えば、モーダルウィンドウのコンポーネントを動的インポートすることで、モーダルが開かれるまでコンポーネントを読み込まないため、初期読み込み時間を短縮できます。

2.2 ルートベースのコード分割

Next.jsでの実装

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割

ルートベースのコード分割により、各ページに必要なコードだけを読み込むことができます。これにより、初期読み込み時のJavaScriptの量を削減し、パフォーマンスを向上させます。例えば、トップページに必要なコードだけを読み込むことで、他のページのコードを読み込む必要がなくなり、初期読み込み時間を短縮できます。

2.3 コンポーネントベースのコード分割

Reactでの実装

import { lazy, Suspense } from 'react';

// 遅延読み込み
const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

コンポーネントベースのコード分割により、必要なコンポーネントだけを読み込むことができます。これにより、初期読み込み時のJavaScriptの量を削減し、パフォーマンスを向上させます。例えば、重いチャートコンポーネントを遅延読み込みすることで、初期読み込み時間を短縮できます。

3. ミニファイと圧縮

3.1 ミニファイ

ツール

  • Terser:JavaScriptのミニファイツール
  • cssnano:CSSのミニファイツール
  • webpack:ビルドツール(自動ミニファイ)

実装例(webpack)

// webpack.config.js
module.exports = {
  mode: 'production', // 自動的にミニファイ
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true, // console.logを削除
          },
        },
      }),
      new CssMinimizerPlugin(),
    ],
  },
};

ミニファイの判断ポイント:不要な空白・改行・コメントの削除で、一般的に 30–50% のサイズ圧縮が見込める。ただし source map を有効にしておかないと、本番でのデバッグが成り立たなくなる。どの環境で適用するか(本番のみ / 開発含む)を事前に決める。

3.2 圧縮

Gzip圧縮

# nginx設定
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

Brotli圧縮

# nginx設定
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

圧縮の判断ポイント:Gzip は対応範囲が広く、一般に 50–70% 削減できる。Brotli はさらに 10–25% 圧縮率が高いが、サーバー/CDN 側の対応が前提になる。導入前に配信インフラの対応状況を確認する。両方使える場合は、クライアントの Accept-Encoding に応じて切り替える構成が扱いやすい。

4. Tree Shaking

4.1 基本的な実装

ES Modulesの使用

// ❌ 悪い例:CommonJS
const utils = require('./utils');
const result = utils.function1();

// ✅ 良い例:ES Modules
import { function1 } from './utils';
const result = function1();

Tree Shaking の判断ポイント:ES Modules 前提で、使用されていないコードをバンドルから除外する仕組み。CommonJS と混在している、あるいは副作用のある import を書いていると効かなくなる。先に決めておくこと:依存ライブラリが ES Modules 対応しているか、副作用フラグ(sideEffects)をどう扱うかを確認する。入れれば必ず効く手段ではない。

4.2 webpackでのTree Shaking

実装例

// webpack.config.js
module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true, // Tree Shakingを有効化
    sideEffects: false, // 副作用がないことを示す
  },
};

package.json

{
  "sideEffects": false
}

5. バンドルサイズの最適化

5.1 バンドル分析

webpack-bundle-analyzer

// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin(),
  ],
};

なぜバンドル分析が重要か?

バンドル分析により、バンドルサイズの内訳を確認できます。これにより、大きな依存関係を特定し、最適化の優先順位を決定できます。

5.2 依存関係の最適化

重複コードの削除

___

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割
0___

依存関係を別のチャンクに分割することで、キャッシュを効率的に使用できます。また、重複コードを削除することで、バンドルサイズを削減できます。例えば、ReactやVueなどのライブラリを別のチャンクに分割することで、ライブラリが更新されても、アプリケーションコードのキャッシュが有効になります。

6. Critical CSS

6.1 基本的な実装

Critical CSSの抽出

___

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割
1___

HTMLでの実装

___

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割
2___

Critical CSS の判断ポイント:ファーストビューに必要な最小限の CSS をインラインで読み込み、残りは遅延させる。LCP に効きやすい一方、Critical CSS の抽出と本体 CSS の二重管理が発生する。先に決めておくこと:更新頻度の高いページで採用すると運用が重くなる。LP など「表示速度が KPI に直結するページ」に限定するか、ビルド時の自動抽出を前提にする。

6.2 Next.jsでの実装

実装例

___

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割
3___

7. 非同期読み込み

7.1 deferとasync

defer

___

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割
4___

async

___

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割
5___

defer/asyncにより、スクリプトの読み込みがHTMLのパースをブロックしません。これにより、ページの読み込み時間を短縮できます。deferは、HTMLのパースが完了した後にスクリプトを実行します。asyncは、スクリプトの読み込みが完了したらすぐに実行します。どちらも、HTMLのパースをブロックしないため、ページの読み込み時間を短縮できます。

7.2 動的スクリプト読み込み

実装例

___

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割
6___

8. 具体的な最適化事例

8.1 事例1:SPAのバンドルサイズ最適化

課題

  • バンドルサイズ:2MB
  • 読み込み時間:5秒
  • 問題:全てのコードを一度に読み込んでいる

解決策

___

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割
7___

結果

  • バンドルサイズ:2MB → 500KB(75%削減)
  • 読み込み時間:5秒 → 1.5秒(70%改善)
  • FID:300ms → 80ms(73%改善)

8.2 事例2:CSS最適化

課題

  • CSSサイズ:200KB
  • LCP:3.5秒
  • 問題:Critical CSSが抽出されていない

解決策

___

// pages/index.js
export default function Home() {
  return <div>Home Page</div>;
}

// pages/about.js
export default function About() {
  return <div>About Page</div>;
}

// Next.jsが自動的にコード分割
8___

結果

  • LCP:3.5秒 → 1.8秒(49%改善)
  • 初期読み込み時間:40%短縮

JavaScript/CSS最適化の要点

  • JavaScript/CSS最適化は、パフォーマンスを改善する重要な方法
  • コード分割により、必要なコードだけを読み込む
  • ミニファイと圧縮により、ファイルサイズを削減
  • Tree Shakingにより、使用されていないコードを削除
  • Critical CSSにより、レンダリングブロックを回避
  • 非同期読み込みにより、HTMLのパースをブロックしない

次のステップ

  1. バンドルサイズを分析(webpack-bundle-analyzer)
  2. コード分割を実装(動的インポート、ルートベース分割)
  3. ミニファイと圧縮を設定(Terser、Gzip/Brotli)
  4. Tree Shakingを有効化(ES Modules、webpack設定)
  5. Critical CSSを抽出(critical、inline)
  6. 効果を検証(パフォーマンス測定)

次に読むおすすめの記事

JavaScript/CSS最適化について理解を深めたら、以下の記事も参考にしてください:

より深く学ぶ

実践的な活用

関連する基礎知識

参考資料・引用元


ご相談・お問い合わせはこちら

次の一手

状況に合わせて、選んでください。