🎨

フロントエンドのスタイリング手法の全体像

に公開1

フロントエンド開発におけるスタイリング手法の全体像

フロントエンド開発において、スタイリングは見た目だけでなくメンテナンス性、パフォーマンス、開発体験にも大きく影響します。この記事では、フロントエンド開発で使われる主要なスタイリング手法の全体像をまとめ、それぞれの特徴や適したユースケースを紹介します。

1. グローバル CSS (従来の CSS/プリプロセッサー)

最も基本的で古典的なアプローチ。

純粋な CSS

/* styles.css */
.button {
  background-color: blue;
  color: white;
  padding: 10px 20px;
  border-radius: 4px;
}

.button:hover {
  background-color: darkblue;
}

特徴:

  • 特徴も最も基本的なスタイリング

デメリット:

  • css ファイルを別で作成する必要がある
  • css が適用されるクラス・タグを把握する手間がある
  • html ファイルでクラス命名をする必要がある
  • 詳細度の概念がだるい

⇨ メンテナンス性が低く、ファイルの管理もめんどい

CSS プリプロセッサー (Sass, Less, Stylus)

// button.scss
$primary-color: blue;
$border-radius: 4px;

.button {
  background-color: $primary-color;
  color: white;
  padding: 10px 20px;
  border-radius: $border-radius;

  &:hover {
    background-color: darken($primary-color, 10%);
  }

  &--large {
    padding: 15px 30px;
  }
}

特徴:

  • 変数、関数、ネスト構文などによる生産性向上
  • モジュール化、再利用性の向上
  • BEM, SMACSS, OOCSS などの設計手法と相性が良い

メリット:

  • コード量の削減と保守性の向上
  • コンパイル時の処理(変数計算、関数実行など)
  • 大規模プロジェクトでのファイル分割が容易

デメリット:

  • コンパイルステップが必要
  • CSS とあんま変わらん

2. CSS Modules

コンポーネント指向のアプローチとして登場した CSS Modules は、ローカルスコープの CSS クラス名を自動生成します。

/* Button.module.css */
.button {
  background-color: blue;
  color: white;
  padding: 10px 20px;
}
// Button.jsx
import styles from "./Button.module.css";

function Button({ children }) {
  return <button className={styles.button}>{children}</button>;
}

特徴:

  • クラス名の自動スコープ化(.button.Button_button_xk9v2
  • コンポーネントとスタイルの分離
  • 通常の CSS を書く感覚で利用可能

メリット:

  • 名前衝突の解消
  • コンポーネントとスタイルの明確な関連付け
  • ビルド時に最適化され、ランタイムオーバーヘッドがない

デメリット:

  • 動的スタイリングが少し複雑
  • グローバルスタイルとの併用が必要な場面もある

3. CSS in JS

JavaScript 内でスタイルを定義できた方が楽じゃん、というアプローチ。

ランタイム CSS in JS (styled-components, Emotion)

// Button.jsx (styled-components)
import styled from "styled-components";

const Button = styled.button`
  background-color: ${(props) => (props.primary ? "blue" : "gray")};
  color: white;
  padding: 10px 20px;
  border-radius: 4px;

  &:hover {
    background-color: ${(props) => (props.primary ? "darkblue" : "darkgray")};
  }
`;

export default Button;

特徴:

  • JavaScript の変数やロジックを直接スタイルに利用可能
  • 条件付きスタイリングが容易
  • テーマ機能と相性が良い

メリット:

  • スコープ化されたスタイル
  • コンポーネントとスタイルの共存
  • 動的スタイリングの強力さ

デメリット:

  • ランタイムオーバーヘッド
  • バンドルサイズの増加
  • SSR の複雑さ ⇨ RSC についていけず、最近 styled-components はメンテナンスモードに突入

ゼロランタイム CSS in JS (Linaria, vanilla-extract)

// Button.jsx (Linaria)
import { styled } from "@linaria/react";

const Button = styled.button`
  background-color: ${(props) => (props.primary ? "blue" : "gray")};
  color: white;
  padding: 10px 20px;
  border-radius: 4px;

  &:hover {
    background-color: ${(props) => (props.primary ? "darkblue" : "darkgray")};
  }
`;

export default Button;

特徴:

  • ビルド時に CSS を抽出
  • ランタイムオーバーヘッドなし
  • 型安全性(vanilla-extract の場合)

メリット:

  • CSS in JS の利点を維持しつつパフォーマンスを改善
  • SSR での問題が少ない
  • 実行時の JavaScript 評価がない

4. ユーティリティファースト (Tailwind CSS など)

小さな単一目的のユーティリティクラスを組み合わせるアプローチです。

<button
  className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
  ボタン
</button>

特徴:

  • 小さな単一目的のクラスを組み合わせる
  • HTML に直接スタイルを適用
  • カスタマイズ可能なデザインシステム

メリット:

  • CSS ファイルを書く必要がほとんどない
  • 一貫したデザイントークンの使用
  • 高速な開発と反復
  • 最終的な CSS バンドルが小さい(未使用クラスが除去される)

デメリット:

  • HTML が長くなりがち
  • 学習曲線

5. UI コンポーネントフレームワーク

すぐに使えるコンポーネントとデザインシステムを提供するライブラリです。

// Material UI の例
import Button from "@mui/material/Button";

function MyApp() {
  return (
    <Button variant="contained" color="primary">
      こんにちは世界
    </Button>
  );
}

主な UI フレームワーク

  • Bootstrap - 最も人気の高い CSS フレームワーク
  • Material UI - Google のマテリアルデザインを実装した React コンポーネント
  • Chakra UI - アクセシビリティに配慮した React コンポーネント
  • Ant Design - エンタープライズ向け React コンポーネント
  • Tailwind UI - Tailwind CSS ベースのコンポーネントライブラリ

メリット:

  • 開発速度の大幅な向上
  • 一貫した UI と UX
  • アクセシビリティ対応が組み込まれている場合が多い
  • 様々なインタラクションがすでに実装済み
  • figma のプラグインに対応していればデザインもかなり楽

デメリット:

  • カスタマイズの難しさ
  • バンドルサイズの増加
  • フレームワーク特有の慣習に縛られる

流行

今まで何社か開発に携わらせてもらっていますが、どこも Tailwind CSS を使っていて、一強かなという所感です。
styled-components がメンテモードに入るなど、比較的頑張っていた CSS in JS も下火な印象。

 
 
 
 
以上です。

KA projects

Discussion

junerjuner

この内容であれば

// button.scss
$primary-color: blue;
$border-radius: 4px;

.button {
  background-color: $primary-color;
  color: white;
  padding: 10px 20px;
  border-radius: $border-radius;

  &:hover {
    background-color: darken($primary-color, 10%);
  }

  &--large {
    padding: 15px 30px;
  }
}

これでもいいのでは?
(※ただし、 css nesting では 親の名前を変更する機構は無い為、複数のclassを指定する構文となる

// button.css
:where(:root) {
  $primary-color: blue;
  $border-radius: 4px;

  .button {
    background-color: $primary-color;
    color: white;
    padding: 10px 20px;
    border-radius: $border-radius;

    &:hover {
      background-color: oklch(from var($primary-color) calc(l * .9) c h);
    }

    &.large {
      padding: 15px 30px;
    }
  }
}

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_nesting

https://developer.chrome.com/blog/css-relative-color-syntax?hl=ja