サービスを長く運用する上で、CSSをどう管理するかが課題になってきます。 チームに後からルールを取り入れると対応に苦労するので、立ち上げ時から一定のルールに従って実装した方がよいでしょう。 ここでは、そのルールについて解説します。

メリット

まず、ディレクトリ構成と命名規則を定めることで、以下のようなメリットがあります。

  • メンテナンス性が向上する
  • 開発速度が上がる
  • コンポーネント化により、統一されたUIを提供できる

前提

今回は、基本的に以下を前提としています。 前提が異なっていても参考になる部分はあると思いますが、その際は適宜読み替えてください。

  • SCSSを導入していること
  • BEMやSMACSSといった、なにかしらのルールを採用していること

ディレクトリ構成と命名規則

CSSのディレクトリ構成と命名規則は、以下のように配置・命名します。 それぞれについての詳細は後述します。

stylesheets/
├── application.scss     --- (1)
├── base.scss            --- (2)
├── components/          --- (3)
│   └── (component).scss
├── lib/                 --- (4)
│   ├── functions.scss
│   ├── mixins.scss
│   └── variables.scss
├── modules/             --- (5)
│   └── (block).scss
├── patches/             --- (6)
│   └── (page).scss
└── vendor/              --- (7)
    └── (library).scss

各項目の説明

(1) application.scss

ここでは、基本的に他のSCSSの@importのみを行ないます。 外部ライブラリのCSSをインポートする場合は、先頭に記述します。

例:

// 外部ライブラリのCSS
@import 'normalize';

// アプリケーションのCSS
@import 'lib/*';
@import 'base';
@import 'components/*';
@import 'modules/*';
@import 'vendor/*';
@import 'patches/*';

(2) base.scss

ここでは、要素や属性、セレクタといった、ベースとなるセレクタそのものへのスタイルを定義します。

例:

body {
  color: $base-color;
  font-family: 'Helvetica Neue', 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif;
}

a {
  color: $primary-color;
  text-decoration: none;

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

(3) components/

ここでは、ボタンやリストビューといった、サイト全体で再利用可能な部品を定義します。

例:button.scss

.button {
  display: inline-block;
  padding: 8px 12px;
  border-width: 1px;
  border-style: solid;
  background-color: #fff;

  &-default {
    border-color: whiten($base-color, 90%);
    color: whiten($base-color, 50%);
  }

  &-primary {
    border-color: $primary-color;
    color: $primary-color;
  }
}

(4) lib/

ここでは、各SCSSから利用するもの(関数、ミックスイン、変数など)を定義します。

例:functions.scss

@function whiten($color, $weight) {
  @return mix($color, #fff, 100% - $weight);
}

例:mixins.scss

@mixin clearfix {
  * {
    zoom: 1;
  }

  &::before,
  &::after {
    display: table;
    content: ' ';
  }

  &::after {
    clear: both;
  }
}

例:variables.scss

$primary-color: #39c;
$base-color: darken(mix(#333, $primary-color), 20%);

(5) modules/

ここでは、コンポーネントの組み合わせでは実現できない部分を定義します。 BEMでいうブロック、SMACSSでいうモジュールがこれにあたります。

例:header.scss

.header {
  margin-bottom: 20px;
  padding: 20px 0;
  border-bottom: 1px solid whiten($base-color, 90%);

  &-title {
    font-family: 'Noto Sans', sans-serif;
    font-size: 120%;
  }

  &-description {
    color: whiten($base-color, 20%);
    font-size: 80%;
  }
}

(6) patches/

特定のページのみ、コンポーネントやモジュールを上書きしたい場合ここに定義します。

例:home.scss

.home {
  .header {
    padding: 40px 0;
  }
}

(7) vendor/

外部ライブラリ標準のスタイルを上書き・追加したい場合ここに定義します。

例:font_awesome.scss

.fa-hatena {
  &:before {
    content: 'B!';
    font-family: Verdana;
    font-weight: bold;
  }
}

ポイント

新しくページや機能などを追加する際、コンポーネントにまとめられるのであれば、可能な限りまとめ、モジュールやパッチへの記述を少なくします。 こうすることで、コンポーネントを組み合わせるだけでデザインができあがり、サイト全体で統一されたUIを提供できるようになります。

モジュールやパッチの記述量が増えてしまうと、ページ・機能によってスタイルがバラバラになり、またメンテナンスもしづらくなります。

おわりに

もちろん、ここで説明したディレクトリ構成・命名規則がすべてのチームにとってベストではありません。 重要なのは、自分たちのルールを決め、それに従い開発していくことです。 長く運用するサービスを制作する際は、ぜひ参考にしてみてください。