Help us understand the problem. What is going on with this article?

おれおれCSS設計・コーディングガイド2015冬の陣

More than 3 years have passed since last update.

はじめに

以前、以下のような記事を投稿しました。
おれおれcss設計・構成案

記事を書いてから1年、基本的な考え方は変わっていませんが、実際のプロジェクトでの採用にあたり構成はちょこちょこと試行錯誤をしてきました。

そこで改めて、現在私がCSSを設計する際の考え方・コーディングルールを整理してみました。個人的に採用しているものなので、使えるかどうかは分かりませんが、何かの役に立つこともあるだろうと思い投稿してみます。

構成の設計・コーディングルールの作成にあたっての考え方

根底にあるもの

  • Keep it simple
  • Don’t repeat yourself

独自のもの

  • コーディングルールも含め、共通ルールは最低限の必須事項のみにとどめる
  • その他は任意事項として個人の裁量に任せる(=ある程度の知識・スキルを要求してしまう)

必須事項の判断基準

  • そもそも動作に必要なもの
  • 守らないと間違いなく破綻しうるもの
  • 守らないと大きく混乱を招きそうなもの
  • 決まっていないと著しく効率が落ちそうなもの

任意事項の判断基準

  • 実際の動作に(さほど)支障がないもの
  • 制作者の好みに左右されるもの
  • 後で機械的にどうにかできるもの
    • csscombや整形ツールなど

目次

  • 必須: 前提条件
    • sassのバージョンとファイル形式について
    • コンパイルについて
    • コンパイル形式について
    • 外部ライブラリ・フレームワークについて
    • プレフィックスについて
    • スタイルガイドの使用
  • 必須: フォルダ・ファイル構成
    • /scss/...
    • /vendor/...
    • /preset/...
    • /project/...
    • style.scss
  • 必須: スタイルの命名ルール
    • BEM式命名
    • 接頭辞について
    • 禁止事項
  • 任意事項
    • 任意とする例
    • 任意とする例(特にスキルを要求するかも)
  • 終わりに

必須: 前提条件

これはプロジェクトに取り掛かる前に、メンバーが持っておくべき共通認識を示しています。

sassのバージョンと形式について

  • 3.4以上
  • scss形式

※バージョンは適宜

コンパイルについて

ツールは問いませんが、ファイル内にコンパイルできない機能が存在する場合は対応したツールを使用してもらいます。

コンパイル形式について

  • スタイルは'expanded'を採用
    • ※納品時に圧縮するかどうかは検討
    • ※圧縮時にはライブラリ・フレームワーク内のライセンス表記を消さないように
  • style.cssという1つのファイルに結合して出力する
  • ただしセレクタ数が4096を超えるときは応相談(旧IEでバグが存在するため)

外部ライブラリ・フレームワークについて

  • あらかじめ決めたもののみ使用する
  • 追加する際は応相談(きちんと周知させる)
  • ここでは以下を採用
    • normalize
    • font-awesome
    • bourbon
    • bourbon-neat

プレフィックスについて

  • Autoprefixerを使用
  • 以下の設定を満たすならツールは問わない
  • 'last 2 versions', 'ie 9', 'ios 6', 'android 4'

※設定内容は適宜

スタイルガイドの使用

汎用的なモジュールをまとめたスタイルガイドを生成し、新しくモジュールを追加する際には確認・更新するようにします。

必須: フォルダ・ファイル構成

これはコードを書く前に、メンバーが持っておくべき共通認識を示しています。
何をどこに入れてどこに書くか、守らないと破綻待った無しなので必ず守ります。
/module/ /demo/ は状況によって整理します。

フォルダ・ファイル構成.
- /scss/

-- /vendor/
  -- _normalize.scss
  -- /font-awesome/...
  -- /bourbon/...
  -- /bourbon-neat/...

-- /preset/
  -- _variable.scss
  -- _function.scss
  -- _mixin.scss
  -- _mixin-module.scss
  -- _selector.scss

-- /project/
  -- _layout.scss
  -- _module.scss
  -- _pages.scss
  -- _utility.scss
  -- _demo.scss
  -- /module/
    -- _section.scss
    -- _submenu.scss
    -- _grid.scss
    -- _media.scss
    -- _block.scss
    -- _heading.scss
    -- _button.scss
    -- _table.scss
    -- _list.scss
    -- _link.scss
    -- _image.scss
  -- /demo/
    -- _color.scss
    -- _pattern.scss
    -- _icon.scss

-- style.scss

/scss/...

コンパイルするソールファイルをまとめて格納します。

/vendor/...

外部ライブラリ・フレームワークをまとめて格納します。

/preset/...

あらかじめ読み込んでおく設定ファイルをまとめて格納します。
_selector.scss以外では、接頭辞をつけグローバルに使用できることを表し外部フレームワークとの衝突を防ぎます。

  • _variable: グローバル変数をまとめる。変数の接頭辞にg_をつける
  • _function: グローバル関数をまとめる。関数の接頭辞にmy_をつける
  • _mixin: セレクタ内でcssを読み込むのに使うmixinをまとめる。mixinの接頭辞にmy_をつける
  • _mixin-module: モジュールを生成するためのmixinをまとめる。mixinの接頭辞にmy_をつける
  • _selector: 要素セレクタの初期値をまとめる

/project/...

プロジェクトを実際に構築するメインのスタイルをまとめて格納します。
_pages.scss以外では、共通の接頭辞をつけます(詳細は後述)。

  • _layout.scss: 多くのページで共通で使用するユニークなスタイル
  • _module.scss: /module/以下を読み込む
  • _pages.scss: 特定のページでのみ使用するスタイル(数が多くなればmoduleのように分割する)
  • _utility.scss: 余白調整などアドホックなスタイル
  • _demo.scss: /demo/以下を読み込む

/project/module/...

  • 汎用的なモジュールを用途ごとに分割して格納
  • それぞれのファイルで何を定義しているのか、ある程度名前で推測判断できるようにする
  • プロジェクトの状況によって柔軟に変更

スタイルガイドに反映

/project/demo/...

  • 開発時に役に立つ参考用のスタイルを用途ごとに分割して格納
  • プロジェクトで使用する色の一覧
  • プロジェクトで使用する背景画像の一覧
  • プロジェクトで使用するアイコンの一覧 など
  • 実際のモジュールには使用しないので、不要であれば削除する

スタイルガイドに反映

style.scss

すべてのファイルを読み込み、1ファイルとして出力します。

style.scss
@charset "utf-8";
//-------------------------------------------
//partialファイル一式
//※読み込み順は変えないこと
//-------------------------------------------

// vendor
@import "vendor/_normalize";            // 初期化css タグが出力
@import "vendor/font-awesome/__import"; // font-awesomeの読み込み 一部タグが出力
@import "vendor/bourbon/_bourbon";      // FW bourbonの読み込み(mixinのみ)
@import "vendor/bourbon-neat/_neat";    // bourbon依存のgrid生成FW(mixinのみ)

// preset
@import "preset/_variables";     // グローバル変数
@import "preset/_function";      // グローバル関数
@import "preset/_mixin";         // cssを読み込むmixin
@import "preset/_mixin-module";  // モジュールを生成するためのmixin
@import "preset/_selector";      // セレクタの初期値 タグが出力

// project
@import "project/_layout";  // 共通でユニークなスタイル
@import "project/_module";  // 汎用的なスタイル
@import "project/_pages";   // ページ独自のスタイル
@import "project/_utility"; // アドホックなスタイル

@import "project/_demo";    // 開発時に役立つ参考用スタイル

必須: スタイルの命名ルール

これはコードを書く際に、メンバーが持っておくべき共通認識を示しています。
classをどういう風に命名し運用していくか、混乱を避け効率を上げるためにも必ず守ります。

BEM式命名

複数単語を使用する場合は区切りを ハイフン-で繋ぐ

.item-abc {}
.item-2 {} // 数字を使う場合も区切り対象とする

BlockとElementは アンダースコア2つ__で繋ぐ

.block__element {}

階層的にElementのElementであっても並列に書く

// ダメ
.block__element1__element2 {}

// OK
.block__element1 {}
.block__element2 {}

ModifierはBlock, Elment名を省略したマルチクラス式を採用

// ダメ
.block--modifier {}
.block__element--modifier {}

// OK
.block.is-modifier {}
.block__element.is-modifier {}

【メモ】
ModifierはBlock, Elementを省略したシンプルな名前にした方がよいかどうか、いまだに悩みます。それは主なデメリットとして、以下が考えられるからです。

1.複数のBlock, Elementが同時に付与される場合(後述のmix手法)、どれに対してのModifierなのか名前から判断しにくい
2.Modifierの名前自体が重複しがちなので、class名から検索がしにくい

私は省略するケースが多いですが、モジュールの粒度が細かくなりそうな場合(いろんなパターンを用意しておきたい)は省略しないほうが運用面で助かるかもしれません。

出現パターンまとめ

.block {}
.block__element {}
.block.is-modifier {}
.block.has-modifier block__element {}
.block__element.is-modifier {}

接頭辞について

classに接頭辞をつけることで認識性を高め衝突を避けます。

/preset/...ファイル内の変数・関数・mixinは、前述の「フォルダ・ファイル構成」を参照

Blockの接頭辞

  • _layout: 接頭辞に l- をつける
  • _module: 接頭辞に m- をつける
  • _utility: 接頭辞に u- をつける
  • _demo: 接頭辞に demo- をつける
  • jsのフックに使用する場合は js-をつける

_page.scssには共通の接頭辞はつけません。
(使用ページを示す接頭辞をつけることはあり)

Modifierの接頭辞

  • Blockのmodifierには is- or has-、Elementのmodifierにはis-をつける
  • Block・Elementともに自身が変化する場合は is-
  • Blockの変化によりElementが変化する場合は has-
  • 孫要素は排除するためElementにhasは持たせない

禁止事項

装飾のためのID使用を禁止

IDはページ内リンクやjs利用時にのみに制限します。
(IDでもjs利用時はclassと同様に接頭辞にjs-を付与)

Modifierの単独指定を禁止

必ずBlock・Elementと同時に指定します。

// ダメ
.is-modifier {}

// OK
.block.is-modifier {}
.block__element.is-modifier {}

セレクタ単独の指定を禁止

セレクタへの直接的なスタイル設定は避けます。

// ダメ
div {}
div.block {}

ただし以下の場合は許容とします

  1. _selector.scss内や外部ファイルで初期値として使用する場合
  2. Block内のElementとして必ずそのセレクタが使用され、そのセレクタ自身のModifierが存在しない場合(逆に言えば、Modifierが存在するものには必ずclass名を用意する)
// OK
.img-wrap {
  img {}
}

// ダメ
.img-wrap {
  img {
    &.is-modifier {}
  }
}

// OK
.img-wrap {
  &__img {
    &.is-modifier {}
  }
}

[補足]
以下のように同じセレクタが入れ子になりうる場合は、予期しない動作が起きる可能性があるため、やはりclass名を用意するか、子孫セレクタ > を使用するのが望ましいかもしれません。

<li>
  <ul>
    <li></li>
  </ul>
</li>

_utilityの3つ以上の同時使用を禁止

_utilityのclassが3つ以上つく場合は、まとめたスタイルをModuleもしくはModifierとして指定できるようにします。

Block同士の依存関係の禁止

Block内に別Blockを組み込む場合、上位Blockから下位Blockに対して直接スタイルを設定することは避けます。

.item {}

// ダメ
.block {
  .item {}
}

特定Block内でのみスタイルを変更したい場合は、wrap / mix 手法が有効です。

wrap
別Blockを包括するelementを用意してスタイルを上書きします(ただしタグが1つ深くなる)。

wrap.html
<div class="block">
  <div class="block__item">
    <div class="item"></div>
  </div>
</div>
wrap.scss
.item {}

.block {}
.block__item {}

mix
classを複数指定することでスタイルを調整します。

mix.html
<div class="block">
  <div class="block__item item"></div>
</div>
mix.scss
.item {}

.block {}
.block__item {}

extendの使用禁止

@extendの使用は避けます。

任意事項

  • ここでの「任意」とは細かいルールは設けずメンバーの裁量に任せるということ
  • ※状況によっては適宜「必須」へ移行させる
  • ※書き方に関しては、1ファイル内では「なるべく」統一させる

任意とする例

  • ネストでの記述(ただし出力されるcssに無駄がないよう配慮する)
.block {
  &__inner {}
}
// or
.block {}
.block__inner {}

参考記事
Sassで@mixinを作る時に知っておきたい基礎知識
http://qiita.com/nekoneko-wanwan/items/c8498a21ae0e2b2198be

  • スペース・改行・インデントなどの設定
  • プロパティの記述順
  • プロパティの記述方法
    • ショートハンドを使う
    • 1未満の数値は0を省略する
    • カラーの指定 etc...
  • コメントアウトの形式

任意とする例(特にスキルを要求するかも)

  • class名で使用する単語名と単語の省略

    • 前提として極端に省略したものや、省略語が一般的でなさそうなものは避ける
    • ※混乱を招きそうであれば、単語リストを用意するなど周知させる
  • class名で使用する数字の扱い

    • 0埋め(01, 02, 001など)をするかどうか
    • 1の場合は省略するかどうか(結局2以降なかったり、急に増えたりはよくあるため、個人的にはその時点で1つしか無いものにはつけないことが多いです)
  • ModuleとModifierの判断基準

Moduleとしてスタイルを組み込むか、Modifierで対応するか、別Moduleにするか、。。。状況に大きく左右されるため一定のルールが難しいです。頻繁に配置の変更・移動がありそうなものであれば、Moduleの外側に影響を与えるmarginなどは組み込まずにModifierで設定する、など。「必須」への移動・ルール変換が頻発するかもしれません。

終わりに

フォルダ・ファイルの構成は結構気に入っていますが、スタイルの命名ルールはもう少し使いやすくできないかな、とも思っています。
他にもこれは必須にした方がいいんじゃないか、など何かあればご指摘ください!

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away