規律あるcssを運営するにあたって

こんにちは、エンジニアの井戸田です。

弊社ではmamanokoという子育てママさんのための情報サイトを運営しており、Ruby on Railsで実装しています。 今回はmamanokoで実装されているのcssの構成についてお話ししたいと思います。 mamanokoではSMACSSというcssの設計手法や、BEMというフロントエンド設計手法を弊社なりにカスタマイズして使用しています。

フロント面の開発環境は下記のようになっております。

SCSS
Slim
CoffeeScript

まずは本来のSMACSS、BEMについて説明します。

SMACSS

SMACSSとは、 Scalable and Modular Architecture CSS の略で スマックス と読みます。CSSの設計手法で1つであり、 Base(ベース)Layout(レイアウト)Module(モジュール)State(ステート)Theme(テーマ) の5つのルールに分け、それぞれのルールや記述規約が決められているのが特徴です。

smacssで設計する目的

SMACSSを導入することによって、コードの量が減り、CSSの弱点であった下記のことが解決されます。

  • 保守性を高める
  • メンテナンス性を高める
  • デザインを統一することで、ユーザー体験の一貫性を高める

5つのルール

Base - ベースルール

要素そのもののスタイルを定義します。 セレクタを使ってスタイルを変更する場所であるので、idやclassは使用できません。

body {
  background-color: #fff;
  color: #000;
}

a {
  &:hover {
    color: inherit;
  }
}

Layout - レイアウトルール

ページのエリア分けを定義します。 header , footer などよく id 指定するユニークな要素がLayoutに該当すると思います。 Modulestate との区別のため l- というprefixをつけるのが特徴です。このようにすることで、他のルールと区別ができ、管理がしやすくなります。

.l-header {
  height: 48px;
  background-color: #fff;
}

.l-footer {
  background-color: #fff;
  border-top: 1px solid #000;
}

Module - モジュールルール

その名前の通り再利用可能なスタイルを定義します。 ページデザインのcssを書くにあたって、ほとんどがここに定義されると思います。 どこにおいても再利用できるように独立させておきます。

またクラスの書き方は モジュール名-サブクラス の順番で書きます。

.article
  p.article-title タイトル
. article {
  background-color: #fff;
  border: 1px solid #000;

  &-title {
    color: #000;
  }
}

State - ステートルール

状態によってデザインを上書きする時に定義します。 !important を使用してのデザインの変更は避けましょう。 !important を使用することで醜いコードになってしまいます。 ステートルールはモジュール名を付けてあげると、クラス名で被ることはないと思います。

.is-item-active
.is-item-hidden

Theme - テーマルール

テーマルールを使用する機会は少ないです。 他言語対応時、英語や中国語など言語で標準のフォントサイズでは小さい場合があるので、そのような場合にテーマルールを使用することもあります。 theme- というprefixをつけるのが特徴です。

BEM

BEMとは Block , Element , Modifier の頭文字を取ったもので、 ベム と読みます。 コンポーネント化のためのclss命名規則です。

BEMで設計する目的

BEMを導入することによって、パーツごとにclass名を完全に独立したものとできるので、下記のことが解決されます。

  • 再利用性を高める
  • 拡張性を高める
  • 開発の生産性とメンテナンス性を高める

BEMの規約

  • Block
    • 文字通りブロック(塊)。構成のルートとなる要素です。
  • Element
    • Blockに所属する子要素。必ずBlockの中でのみ存在し、単体では使用してはいけません。
  • Modifier
    • 元となるBlock又はElementから変化した状態を示すものです。

上記の元に下記の規約が定められています。

  • BlockやElementで2つ以上の単語の場合はハイフン1つ(-)
  • Modifierで2つ以上の単語の場合はアンダースコア1つ(_)
  • BockとElementはアンダースコアを2個(__)
  • Block又はElementとModifierはハイフンを2個(--)
.articles-list
  .articles-list__item
    .artiles-list__item__title
      | タイトル

  .articles-list__item--state_small
    ・
    ・
    ・

弊社のSMACSSとBEMの構成

まず弊社ではマルチクラス設計を採用しています。 マルチクラス設計とは、HTMLに複数のclassを書いて、スタイルを当てる設計のことです。 マルチクラスを採用することにより、冗長な記述が減り、保守性の向上につながります。

例) ピンクのボタン(.button-pink)と、緑(.button-green)のボタンを定義

/ good

.button {
  padding: 12px 20px;
  background-color: #fd8280;
  border: 1px solid #fd6360;
  border-radius: 2px;
  color: #fff;
  
  &-pink {
    background-color: #fd8280;
    border: 1px solid #fd6360;
  }
  
  &-green {
    background-color: #3de933;
    border: 1px solid #0ce400;
  }
}

/ bad
.button { 
  &-pink {
    padding: 12px 20px;
    background-color: #fd8280;
    border: 1px solid #fd6360;
    border-radius: 2px;
    color: #fff;
  }
  
  &-green {
    padding: 12px 20px;
    background-color: #3de933;
    border: 1px solid #0ce400;
    border-radius: 2px;
    color: #fff;
  }
}

SMACSS

本来では5つのルールに分けるのですが、弊社では7つのルールに分けて使用しています。
smacssでは、ほとんどのスタイルが module に定義されると思うのですが、 module をもっと細かいルールに分けることによって、fatになってしまいがちの module を防いでいます。

  • Base
    本来のSMACSSと同じで、要素そのもののスタイルを定義します。
    セレクタを使ってスタイルを変更する場所であるので、idやclassは使用できません。
a {
  color: #000;
}
  • Component
    component に書くものなのですが、 見出し 部分や ボタン など、どこのページでも使い回す要素をここで定義します。そのため、グローバルなクラス名を付ける必要があります。
    現在のmamanokoでは見出し部分のクラス名は .heading 、ボタン部分のクラス名は .button と付けています。
.heading {
  border-bottom: 1px solid #000;
  padding: 0 8px;
  margin: 0 0 10px
}
  • Module
    moduleも使い回す要素を定義します。componentとの違いとして、グローバルなclass名をつけない要素を定義するということです。主にグローバルなクラス名ではない要素のほどんどが、ここに定義されます。

ユーザページのアバター画像及び、ユーザーネームを表示するヘッダーのcssを作成する場合

.userHeader {
  padding: 20px;
  background-color: #fff;
  
  &_image {
    width: 80px;
    height: 80px;
  }
  
  &_name {
    font-size: 80%;
  }
}
  • Layout
    本来のSMACSSと同じで、header , footer などよく id 指定するユニークな要素のものを記述し、 l- というprefixを付けて他のルールと区別するようにしています。

  • Patch
    使い回しをしない、特定のcssを定義するルールです。現在ではcontroller名ごとにファイルを分けをしており、ファイル内ではactionごとにcssを変更するようにしています。このようにすることによって、特定のページだけcssが変更することができるのを加えて、componentやmoduleのcssを打ち消すことができます。 但し patchを使いすぎると、醜いコードになってしまうので注意が必要です。

.users_controller {
  .edit_action {
    .heading {
      font-size: 80%;
    }
  }
}
  • Lib
    mixinなどの関数や、colorコードを変数で定義するルールです。
    mixinなどの関数を1ファイルにまとめておくことで、保守性を高め、メンテナンスがしやすくなると思います。 またcolorコードを変数で定義することにより、他のルールでcolorコードを設定する場合に、定義した変数を使うので、保守性、メンテナンス性を高めるのはもちろん、ユーザー体験の一貫性を高める効果があると思います。

現在mamanokoではここに定義されたcolorコードの変数を使い、色を濃くするにはscssの関数である darken や、色を薄くするには独自に関数を作成したものを使用しています。

@mixin rounded-s {
  border-radius: 2px;
}

@mixin rounded-m {
  border-radius: 4px;
}
$base-color: #000;
$primary-color: #ff828c;
  • Vendor
    外部ライブラリのcssを書き換えるルールです。現在mamanokoではBootstrapを使用しているのですが、デフォルトでcssが定義されており、うちのサイトにあったデザインにするためcssを書き換えています。

BEM

本来のBEMでは上記でも書いたようなルールがあります。

- BlockやElementで2つ以上の単語の場合はハイフン1つ(-)
- Modifierで2つ以上の単語の場合はアンダースコア1つ(_)
- BockとElementはアンダースコアを2個(__)
- Block又はElementとModifierはハイフンを2個(--)

BEMの本来の形のまま実行してしまうと、下記のようなデメリットがあります。

  • クラス名が冗長になってしまうので、コーディング量が増える
  • 深くネストした要素はクラス名が複雑になってしまう

このデメリットを防ぐために、弊社では独自のルールを制定しています。

弊社のルール

  • BlockとElement又はModiferとElementの区切りはアンダースコアを1つ( _ )
/ good
.block_element
.block-modifier_element

/ bad
.block__element
.block--modifier__element
  • BlockとModifier又はElementとModifierの区切りはハイフンを1つ( _ )
/ good
.block-modifier
.block_element-modifier

/ bad
.block--modifier
.block__element--modifier
  • BlockやElement, Modifierが2つ以上の単語で表す場合キャメルケースを使用する
/ good
.articlesList
  .articlesList_container

/ bad
.articles-list
  .articles-list__container
  • ElementのElementは記述しなくて良い
/ good
.articlesList
  .articlesList_container
    .articlesList_title
    
/ bad
.articlesList
  .articlesList_container
    .articlesList_container_title

いかがでしょうか? SMACSSのルールをより細分化、BEMを冗長性を防ぐためハイフンや、アンダースコアを省略することで、より使いやすくなると思います。 最初は慣れないと思いますが、慣れてこれば簡単に要素のcssを検索することができるのではないでしょうか。

最後まで読んでいただきありがとうございました。