7 CSS (Sass) のコーディングルール #CSS #Sass みんなに公開

私的(あるいはテンマド社の)CSS/SCSSコーディングについてのルールまとめです。

自分自身の整理/備忘録と、自分の書いたコードを引き継ぐなどしていじることになった人に見せる用。随時更新。

ルール設計の指針

  • 覚えるべきことは必要最小限に
  • メンテナンス性の高さを最重要視
  • 開発時に「迷う」「考える」部分を極力減らして余計な事を考えずに済むように

前提

Sassを使う

素のCSSを使うような苦行は避けます。

ほとんど好みの問題ですが、Lessは記法がちょっとよくないので、Sassを使います。
処理速度やツールセットの関係で、本家RubyのSassではなく、node-sassのほうを、大抵はgulp-sassで走らせて使います。

SASS記法ではなく、SCSSのほうを使う

SASSの記法(HAMLっぽいやつ)は使わず、SCSS(よりCSSっぽい記法)のほうを使います。

学習コストが低いことと、JSライブラリ付属のCSSやネットで公開されているコードなどを取り込みやすいからです。

Autoprefixerなどのツールを活用

AutoprefixerなどPostCSS方面のツールを活用して、.scssファイルにはできる限り最新仕様ベースのCSSを、ベンダープレフィックスなしで書くようにします。

コーディングルールと命名規則

すべてクラスに対してスタイル指定し、IDで指定はしない

#main {
  color:red;
}
#main ul{
  color:green;
}
BAD
.main{
  color:red;
}
.main-list{
  color:green;
}
GOOD

ID指定でスタイルを書くことはしません。全てクラスで指定します。

IDは詳細度(selector's specificity)が高すぎて、他の場所でカスケードしてスタイルを上書きしようとした時!importantを多発しなくてはいけなくなったり、あれこれと障害になるためです。

初期化/リセットする部分以外で、タグに対してスタイル指定をしない

.some-class ul{
  color:red;
}
ul.some-class li{
  color:red;
}
BAD
.some-class-list{
  color:red;
}
.some-class-list-item{
  color:red;
}
GOOD

リセット/初期化する部分を除いて、タグ名で、あるいはタグ名を含めたスタイル指定は一切せず、面倒でも全部クラスを割り振り、クラスに対していスタイル指定をします。

タグの構造は、制作していく上の都合やJSとの兼ね合いで変えることがよくあるので、その際に書き換える手間を減らし、HTMLの構造とCSSによるスタイリングを極力分離しておくためです。

例外として、たとえばMarkdownパーサが出力するHTMLなど、クラスの割り当てられない部分で、かつタグにスタイルを指定するのが妥当な部分は除きます。

クラス名はハイフン区切りで全て小文字

.snakecase_class{
  color:red;
}
.camelCaseClass{
  color:red;
}
.Has-Capital-CLASS{
  color:red;
}
BAD
.good-class-definition{
  color:red;
}
GOOD

クラス名は小文字の英数字+ハイフン区切りを基本とします。

シフトキー押さなくていいので楽ですし、大文字小文字のタイプミスでスタイルが当たらなくてうんうん悩む事も減るからです。

例外として、Angularアプリを書いていてdirective名とCSSの接頭辞を合わせたい、CSS増えすぎて小文字だけだとつらい、などの理由がある時に、接頭辞部分(一番先頭の部分)に限り、camelCaseを使ったりするのはアリです。

クラス名の先頭部分と、それが定義されているファイル名を一致させる【重要】

クラス名の先頭部分(最初のハイフンが登場する前の部分)と、それが定義されているファイル名が必ず一致するようにします。
たとえば、.mypage-navというクラスのスタイル指定は、_mypage.scssに書くようにします。

/* _header.scss */
.my-awesome-header{ ... }
.alternative-header{ ... }
BAD
/* _header.scss */
.header{ ... }
.header-logo{ ... }
.header-nav{ ... }
GOOD

もし、一つのファイルにクラス定義が多くなってきた場合は、ファイルを分けてもいいのですが、その場合も「クラスの先頭部分とファイル名が一致するようにする」というルールは維持します。

例えば.main-xxxxというクラスが非常に多くなって_main.scssが肥大化し、メンテしづらくなってきたとして、.main-content-で始まるものを別ファイルに切り出したら、そのファイルは_main-content.scssにします。

こうすることで、クラス名を見た瞬間にそれがどのファイルに書かれているのかがわかるようになり、開発効率が上がります。
同時に他のファイルに書かれたクラスと同じクラスをうっかり指定して上書きしてしまうような事故も防げます。

※ 例外として、状態などを表す.mode-で始まるクラスだけ、ファイル名と関係なく使うことができます。ただし、.mode-はファイル名に一致するほうのクラスにつなげる(?)形でしか定義してはいけません。

/* _my.scss */
.my-btn .mode-disabled{ ... }
.mode-disabled{ ... }
BAD
/* _my.scss */
.my-btn.mode-disabled{ ... }
.my-btn{
  &.mode-disabled{ ... }
}
GOOD

グローバルなクラスは必ず.g-で始める

サイト全体で使うようなスタイル(たとえばボタンやform要素)は、全て.g-で始まるクラスを使ってスタイル指定します。で、当然、_g.scssに書きます。

 /* サイト全体共通で使うボタンのスタイル */
.g-btn{ background:$g_color_brand; }

/* サイト全体共通で使うinput type="text" の要素のスタイル */
.g-input-text{ font-size:1rem; }

.g-が頭についたクラスはサイト全体で使われているということになるので、スタイルを変更する時には細心の注意が必要です。それを明示するためにこのようなルールにしています。

※グローバルなクラス(.g-のクラス)を使うのはどういう時か?

.g-は「編集に注意の要るもの」であることを知らせるためにあるルールなので、闇雲に.g-をつけてはいけません

たとえば、サイト上のサイトの共通のヘッダであれば、それは確かにサイトの色々なページで使われていますので「.g-」とすべきかもと思うところですが、それは「.header-」として「_header.scss」に書かれるべきです。(そのほうが管理上もわかりやすいです)

.g-の基本的な指針としては

  • 単純にほぼ同じマークアップで何度も使いまわすだけのもの(たとえばサイトの共通ヘッダやコンポーネント的なもの)には.g-はつけません。その要素をよく表す名前(.header-など)をつけましょう。(そしてHTML側もマクロとかパーシャルに切り出す、継承を活用するなどしてDRYにしておきましょう)
  • WebサイトのテンプレートをできるだけDRYに書いて、それでも複数の箇所で(さらにそれぞれ微妙にスタイルが違ったりしてスタイルを上書きするような形で)使いまわすことになったものに.g-のクラスを割り当てます。
  • その他、例えば_header.scss上で_form.scssに書いてある.form-で始まるクラスのスタイルを上書きしたい、みたいな場面に出くわした場合、↓のネストのルールに触れるので、その上書きしたいクラスは.g-に移すべきです。

※DRY=Don't repeat yourself。要するに同じコードをコピペしたりして二度以上書かないようにする、ということ。何かしらのよいテンプレートエンジンを活用して実現しましょう

クラスのネストはしない。必要な場合に限りに2階層のネストまではOK

クラスのネストは基本的にはしません
既存のクラスを上書きするような形で新しい定義をしたいような、必要な場合に限り2階層のネストが許されます。

.my-parent .my-child .my-element{ ... }
/* ↓ネームスペースとかコンポーネント的な発想でこうするのも害が多いのでダメです */
.my-parent{
  .my-child{ }
  .my-child2{ }
}
BAD
.my-parent{ ... }
.my-child{ ... }
.my-parent-altenate{
  .my-child{ ... }
}
GOOD

同時に、.g-ではじまるグローバルなクラス以外は、別ファイル上で定義されているクラスをネストして上書きすることは避けます。

/* _my.scss で… */
.my-list{
  .user-list-item{
    color:red;
  }
}
BAD

基本的にやっていいのは

.my-module{
  .g-btn{ /* グローバルなクラスの定義を上書き */ }
}

といった感じで、.g-で始まるグローバルなクラスのスタイルを、グローバルじゃないクラスの中で上書きしてカスタムするような場合と、

.my-module{ ... }
.my-module-element{ ... }
.my-module-alt{ ... }
.my-module-alt{
  .my-module-element{ ... }
}

といった感じで、同じファイル内に定義された既存のクラス上書きしてカスタムするためにネストさせる場合のみで、それ以外のネストはできる限り避けます。

せっかくSassなのにネストという便利機能を使わないのももったいない気はしますが、クラスをネストさせて多く重ねると詳細度が上がり、他の部分でそれを上書きするスタイルを定義したい時に、!importantの多用や、無駄に詳細度の高い記述を要求されるようになり、長くメンテナンスを続けると地獄のようなCSSになりますので避けたほうがよいです。

@keyframeのアニメーション名の先頭部分などもファイル名に合わせる

アニメーション名などに限らず、とにかく名前を付ける必要のあるものは、名前の先頭部分とファイル名が一致するようにします。

JavaScriptとの連携

JavaScriptから使うクラスは「.x-」で始め、CSS側でそのクラスは絶対に使わない

JavaScriptで要素の取得やDOM操作のために使うclassは、全て「.x-」で始めるようにし、この「.x-」で始まるクラスに対してはCSSでスタイル指定をしてはいけません
当然、_x.scssという名前のファイルは作成禁止です。

「.x-」をつけるのは、HTML上で、このクラスをJavascriptで操作に使っているので変更に注意が必要、ということを明示するためです。

一方、JavaScriptでのDOM操作と、CSSでのスタイル指定は切り離しておいたほうがよいので、「.x-」のついたクラスに対してスタイルを当てることは絶対にしないようにします。

/* .x-が頭についたクラスはCSSに一切書いてはいけません */
.x-list-element{ color:red; } 
BAD

JavaScriptとCSSの連携については、後述の「.mode-」のついたクラスでコントロールします。

JavaScriptで使うIDは「x」で始めたcamelCaseとし、CSS側でそのIDは絶対に使わない

jsでのDOM操作のためにIDを割り当てる場合はid="xSomeElement"というようにxから始まるcamelCaseで指定します。

CSS側ではこのIDに対してスタイルを当てるようなことはしてはいけません(まあ、そもそもIDは使ってはいけない事になってますが…)

JavaScriptからスタイルに関わる変更をする場合は.mode-というクラスを通して行う

JavaScriptから要素の表示/非表示や見た目など、スタイルに関わる部分を変更したい場合は、.mode-が頭についたクラスをつけたり外したりすることで行います。

$('.x-list-item').show();
$('.x-list-item').addClass('show');
$('.x-list-item').css({'display':'block'});
BAD
$('.x-list-item').addClass('mode-show);
GOOD

JavaScriptで表示非表示をコントロールしたり、styleを直接いじってアニメーションさせたりするのはできるだけ避け、CSSのtransitionやanimationを活用するようにします。

Sass

Sassの変数名はスネークケースで書く

ハイフンは使わず、$some_sass_varsといったような、アンダースコア区切り+小文字のスネークケースで変数を定義します。

$base-margin: 12px;
$basePadding: 12px;
BAD
$base_margin: 12px;
$base_padding: 12px;
GOOD

ハイフンを使わないのは、クラス名と区別をつけやすくして検索の時に邪魔にならないようにするためと、SASSだと「-」が演算子としても機能するので、それとの区別をつけて意図しない演算やエラーの発生を防ぐためです。

Sassの変数名も、ファイル名と一致させる

クラス名と同じく、Sassの変数名も、ファイル名と同じ接頭辞で始めます。

/* GOOD */
$header_color: #999;

/* BAD */
$color_of_header: #999;
_header.scss

例外として、下記のとおり「$g_」で始まるものだけルールが違います

Sassのグローバル変数は_vars.scssに書き、$g_で始める

/* _vars.scssにグローバル変数をまとめておく */

$g_color_border: #999;
$g_color_text: #333;

$g_radius: 5px;
$g_header_height: 30px;

...
_vars.scss

※ 別にグローバル変数名を$vars_とかにしてもいいんだけど長いしグローバル変数っぽくないのでね。。

@extendはなるべく避ける

@extendは、extend元のスタイルを変更した時に影響する範囲が見えず、意図しない部分に影響が出たりするのでできる限り避けます。

@extendを活用したSASSライブラリなどを使う場合は除きます。

mixinも時に避ける

何かと便利なので使ったりしますが、mixinも時にちょっと避け気味にします。
mixinを使って似たような定義をたくさん作るなら、それを一つのclassにしてカスケードしてオーバーライドしたほうがいい場合も多いからです。

レスポンシブ対応はmixinで行う

ここはまだ練ってるところではありますが。
今のところ以下のようなコードでやってます。


/* responsive utility */
@mixin screen_hh{
  @media screen and (max-width: $g_width_hh_max){
    @content;
  }
}
@mixin screen_sm{
  @media screen and (max-width: $g_width_sm_max){
    @content;
  }
}
@mixin screen_md{
  @media screen and (max-width: $g_width_md_max){
    @content;
  }
}
@mixin screen_sm_only{
  @media screen and (min-width: $g_width_hh_max + 1) and (max-width: $g_width_sm_max){
    @content;
  }
}
@mixin screen_md_only{
  @media screen and (min-width: $g_width_sm_max + 1) and (max-width: $g_width_md_max){
    @content;
  }
}
@mixin screen_lg_only{
  @media screen and (min-width: $g_width_md_max + 1){
    @content;
  }
}
_mixins.scss

というのを用意して

.my-list{
  font-size:16px;
  @include screen_hh{
    /* handheldサイズ時のスタイルをここに書く */
    font-size:14px;
  }
}
_my.scss

※もっとスマートにわかりやすく書ける方法があれば知りたい

まとめ

色々書いてはありますが、要するにまずは

  • ハイフン区切りで小文字のclassしか書かず、classを可能な限りネストしない
  • class(など、何かしらの名前をつけるもの)の名前の先頭部分と、それが書いてあるファイル名を一致させる
  • 「g」がついてたらグローバルなので変更は要注意

これを守ってればだいたいOKってな感じです。

Happy Coding! 🎉

7

メモを他の人に見せる

このメモを見せたい人に、このURL(今開いているページのURLです)を教えてあげてください

コメント(2)

  • someone

  • someone

  • zk33 zk33

    ほんとだ。ご指摘ありがとうございます。修正しました。

  • someone

    「Sassの変数名はスネークケースで書く」のとこの例が両方「BAD」になってますよ。