CSS (Sass) のコーディングルール #CSS #Sass version 17
#CSS ( #(SCSSass) / #SASS )の #コーディングルール
私的(あるいはテンマド社の)CSS/SCSSコーディングについてのルールまとめです。
自分自身の整理/備忘録と、自分の書いたコードを引き継ぐなどしていじることになった人に見せる用。
自分自身の整理/備忘録と、自分の書いたコードを引き継ぐなどしていじることになった人に見せる用。随時更新。
# ルール設計の指針
* メンテナンス性の高さを重視
* 開発時に「迷う」「考える」部分を極力減らして余計な事を考えずに済むように
* メンテナンス性の高さを最重要視
* 覚えるべきことは必要最小限に
# 前提
## Sassを使って書く
## Sassを使う
素のCSSを使うような苦行は避けます。
ほとんど好みの問題ですが、Lessは記法がちょっとよくないので、Sassを使います。
処理速度やツールセットの関係で、本家RubyのSassではなく、[node-sass](https://github.com/sass/node-sass)のほうを、大抵は[gulp-sass](https://github.com/dlmanning/gulp-sass)で走らせて使っています。
処理速度やツールセットの関係で、本家RubyのSassではなく、[node-sass](https://github.com/sass/node-sass)のほうを、大抵は[gulp-sass](https://github.com/dlmanning/gulp-sass)で走らせて使います。
## Autoprefixerなどのツールを活用して効率よく
vendor-prefix対策などは、Compass等のSassライブラリでやるのではなく、[Autoprefixer](https://github.com/postcss/autoprefixer)など[PostCSS](http://postcss.org/)方面のものを使います。
## SASS記法ではなく、SCSSのほうを使う
SASSの記法(HAMLっぽいやつ)は使わず、SCSS(よりCSSっぽい記法)のほうを使います。
学習コストが低いことと、JSライブラリ付属のCSSやネットで公開されているコードなどを取り込みやすいからです。
## Autoprefixerなどのツールを活用
[Autoprefixer](https://github.com/postcss/autoprefixer)など[PostCSS](http://postcss.org/)方面のツールを活用して、`.scss`ファイルにはできる限り最新仕様ベースのCSSを、ベンダープレフィックスなしで書くようにします。
# コーディングルールと命名規則
## すべてクラスに対してスタイル指定し、IDで指定はしない
```scss:BAD
#main {
color:red;
}
#main ul{
color:green;
}
```
```scss:GOOD
.main{
color:red;
}
.main-list{
color:green;
}
```
ID指定でスタイルを書くことはしません。全てクラスで指定します。
IDは詳細度(selector's specificity)が高すぎて、他の場所でカスケードしてスタイルを上書きしようとした時`!important`を多発しなくてはいけなくなったり、あれこれと障害になるためです。
## 初期化/リセット的なことをする部分以外で、タグに対してスタイル指定をしない
## 初期化/リセットする部分以外で、タグに対してスタイル指定をしない
```scss:BAD
.some-class ul{
color:red;
}
ul.some-class li{
color:red;
}
```
```scss:GOOD
.some-class-list{
color:red;
}
.some-class-list-item{
color:red;
}
```
リセット/初期化する部分を除いて、タグ名で、あるいはタグ名を含めたスタイル指定は一切せず、面倒でも全部クラスを割り振り、クラスに対していスタイル指定をします。
タグの構造は、制作していく上の都合やJSとの兼ね合いで変えることがよくあるので、その際に書き換える手間を減らし、HTMLの構造とCSSによるスタイリングを極力分離しておくためです。
例外として、たとえばMarkdownパーサが出力するHTMLなど、クラスの割り当てられない部分で、かつタグにスタイルを指定するのが妥当な部分は除きます。
## クラス名はハイフン区切りで全て小文字
```scss:BAD
.snakecase_class{
color:red;
}
.camelCaseClass{
color:red;
}
.Has-Capital-CLASS{
color:red;
}
```
```scss:GOOD
.good-class-definition{
color:red;
}
```
クラス名は小文字の英数字+ハイフン区切りを基本とします。
シフトキー押さなくていいので楽ですし、大文字小文字のタイプミスでスタイルが当たらなくてうんうん悩む事も減るからです。
例外として、Angularアプリを書いていてdirective名とCSSの接頭辞を合わせたい、CSS増えすぎて小文字だけだとつらい、などの理由がある時に、接頭辞部分(一番先頭の部分)に限り、camelCaseを使ったりするのはアリです。
## クラス名の先頭部分と、それが定義されているファイル名を一致させる
クラス名の先頭部分(最初のハイフンが登場する前の部分)と、それが定義されているファイル名が必ず一致するようにします。
たとえば、`.mypage-nav`というクラスのスタイル指定は、`_my.scss`に書くようにします。
```css:GOOD
/* _header.scss */
.header{ ... }
.header-logo{ ... }
.header-nav{ ... }
```
```css:BAD
/* _header.scss */
.my-awesome-header{ ... }
.alternative-header{ ... }
```
もし、一つのファイルにクラス定義が多くなってきた場合は、ファイル分けも可能ですが、ルールは同じです。
例えば`.main-xxxx`というクラスが非常に多くなって`_main.scss`が肥大化し、メンテしづらくなってきた場合、`.main-content-`で始まるものを別ファイルに切り出して`_main-content.scss`に書くようにします。
もし、一つのファイルにクラス定義が多くなってきた場合は、ファイルを分けてもいいのですが、その場合も「クラスの先頭部分とファイル名が一致するようにする」というルールは維持します。
例えば`.main-xxxx`というクラスが非常に多くなって`_main.scss`が肥大化し、メンテしづらくなってきたとして、`.main-content-`で始まるものを別ファイルに切り出したら、そのファイルは`_main-content.scss`にします。
こうすることで、クラス名を見た瞬間にそれがどのファイルに書かれているのかがわかるようになり、開発効率が上がります。
同時に他のファイルに書かれたクラスと同じクラスをうっかり指定して上書きしてしまうような事故も防げます。
## グローバルなクラスは必ず`.g-`で始める
サイト全体で使うようなスタイル(たとえばボタンやform要素)は、全て`.g-`で始まるクラスを使ってスタイル指定します。で、当然、`_g.scss`に書きます。
`.g-`が頭についたクラスはサイト全体で使われているということになるので、スタイルを変更する時には注意が必要です。
```css:例
/* サイト全体共通で使うボタンのスタイル */
.g-btn{ background:$g_color_brand; }
## クラスのネストは2階層まで、を基本とする
/* サイト全体共通で使うinput type="text" の要素のスタイル */
.g-input-text{ font-size:1rem; }
```
`.g-`が頭についたクラスはサイト全体で使われているということになるので、スタイルを変更する時には細心の注意が必要です。
## クラスのネストは2階層まで
クラスのネストは基本的に2階層までです。
Sassだと深いネストなど楽に書けるのでついついやってしまいますが避けます。
Sassだと深いネストなど楽に書けるのでついついやってしまいますがよほどの理由がない限り避けます。
```css:BAD
.my-parent .my-child .my-element{ ... }
```
```css:GOOD
.my-parent{ ... }
.my-child{ ... }
.my-parent-altenate{
.my-child{ ... }
}
```
また、別ファイルで定義されているクラスをネストして上書きすることもできるだけ避けます。
```css:BAD
/* _my.scss で… */
.my-list{
.user-list-item{
color:red;
}
}
```
基本的にやっていいのは
```css
.my-module{
.g-btn{ /* グローバルなクラスの定義を上書き */ }
}
```
といった感じで、`.g-`で始まるグローバルなクラスのスタイルを、グローバルじゃないクラスの中で上書きしてカスタムするような場合と、
```css
.my-module{ ... }
.my-module-element{ ... }
.my-module-alt{ ... }
.my-module-alt{
.my-module-element{ ... }
}
```
といった感じで、同じファイル内に定義されたクラス同士でネストさせる場合です。
それ以外のネストはできる限り避けます。
クラスをネストさせて多く重ねると詳細度が上がり、他の部分でそれを上書きするスタイルの定義が難しくなるためです。
## `@keyframe`のアニメーション名の先頭部分もファイル名に合わせる
アニメーション名などに限らず、とにかく名前を付ける必要のあるものは、名前の先頭部分とファイル名が一致するようにします。
# Javascriptとの連携
## Javascriptから使うクラスは「.x-」で始め、CSS側でそのクラスは絶対に使わない
Javascriptで要素の取得やDOM操作のために使うclassは、全て「.x-」で始めるようにし、この「.x-」で始まるクラスに対してはCSSでスタイル指定をしては**いけません**。
当然、`_x.scss`という名前のファイルは作成禁止です。
「.x-」をつけるのは、HTML上で、この要素はJavascriptで操作に使っているので変更に注意が必要、ということを明示するためです。
「.x-」をつけるのは、HTML上で、このクラスをJavascriptで操作に使っているので変更に注意が必要、ということを明示するためです。
一方で、JavascriptでのDOM操作と、CSSでのスタイル指定はできるかぎり切り離しておいたほうがよいので、「.x-」のついたクラスに対してスタイルを当てることは絶対にしないようにします。
```css:BAD
/* .x-が頭についたクラスはCSSに一切書いてはいけません */
.x-list-element{ color:red; }
```
JavascriptとCSSの連携については、後述の「.mode-」のついたクラスでコントロールします。
## Javascriptで使うIDは「x」で始めたcamelCaseとし、CSS側でそのIDは絶対に使わない
jsでのDOM操作のためにIDを割り当てる場合は`id="xSomeElement"`というようにxから始まるcamelCaseで指定します。
CSS側ではこのIDに対してスタイルを当てるようなことはしてはいけません(まあ、そもそもIDは使ってはいけない事になってますが…)
## JSとCSSで連携する場合は`.mode-`というクラスを通して行う
## JavascriptとCSSで連携する場合は`.mode-`というクラスを通して行う
Javascriptから要素の表示非表示や見た目など、スタイルに関わる部分を変更したい場合は、`.mode-`が頭についたクラスをつけたり外したりすることで行います。
要素のアニメーションなどはできる限りCSSのtransitionやanimationで行います。
Javascriptでのアニメーションは極力避け、できる限りCSSのtransitionやanimationで行います。
その際、JS側では`.mode-`と頭についたクラスの追加と削除のみを行い、CSS側ではその`.mode-`と頭についたクラスを使ってアニメーション
# Sass
## Sassの変数名はスネークケースで書く
ハイフンは使わず、`$some_sass_vars`といったような、アンダースコア区切り+小文字のスネークケースで変数を定義します。
```scss:BAD
$base-margin: 12px;
$basePadding: 12px;
```
```scss:BAD
$base_margin: 12px;
$base_padding: 12px;
```
ハイフンを使わないのは、クラス名と区別をつけやすくすることと、SASSだと「-」が演算子としても機能するので、それとの区別をつけて意図しない演算やエラーの発生を防ぐためです。
## SASSの変数名も、ファイル名と一致させる
変数名は、ファイル名と同じ接頭辞で始めます。
```scss:_header.scss
/* GOOD */
$header_color: #999;
/* BAD */
$color_of_header: #999;
```
唯一の例外として、下記のとおり「$g_」で始まるものだけルールが違います
## SASSのグローバル変数は`_vars.scss`に書き、`$g_`で始める
```scss:_vars.scss
/* _vars.scssにグローバル変数をまとめておく */
$g_color_border: #999;
$g_color_text: #333;
$g_radius: 5px;
$g_header_height: 30px;
...
```
※ 別にグローバル変数名を`$vars_`とかにしてもいいんだけど長いのでね。。
## `@extend`は出来る限り避ける
`@extend`は、extend元のスタイルを変更した時に影響する範囲が見えず、意図しない部分に影響が出たりするのでできる限り避けます。
代わりに、
* 同じスタイルならできるだけ同じクラス名を割り振る
* 似たスタイルならクラスを複数振って上書きして調整する
* extendsしたいようなクラスは`.g-`のクラスとして定義して、ネストさせる
のを推奨です。
`@extend`を活用したSASSライブラリなどを使う場合は除きます。
## `@mixin`も時に避ける
何かと便利なので使ったりしますが、`@mixin`も時にちょっと避け気味にします。
mixinを使って似たような定義をたくさん作るなら、それを一つのclassにしてカスケードしてオーバーライドしたほうがいい場合も多いからです。
## レスポンシブ対応はmixinで行う
ここはまだ練ってるところです。
今のところ以下のようなコードでやってます。
```scss:_mixins.scss
```
※もっとスマートにわかりやすく書ける方法があれば知りたい
# その他
## BEMなどを使わない理由
BEMは、画面設計がしっかりできていて、CSSの設計に時間がかけられる場合はよいですが、だいたい自分の作るようなものは日々変化の多いものなので、
* ルールとしてやや複雑すぎる
* っていうかどれがBlockでどれがElementでどれがModifierだとかあれこれ余計な事を考えたくない
* 一つのモジュールのつもりで書いていたものの中のパーツをモジュールとして切り出したくなるとかいった変更をしたくなった時にストレス
といった理由で採用していません。
私的(あるいはテンマド社の)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;
}
GOODID指定でスタイルを書くことはしません。全てクラスで指定します。
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
というクラスのスタイル指定は、_my.scss
に書くようにします。
/* _header.scss */
.header{ ... }
.header-logo{ ... }
.header-nav{ ... }
GOOD/* _header.scss */
.my-awesome-header{ ... }
.alternative-header{ ... }
BADもし、一つのファイルにクラス定義が多くなってきた場合は、ファイルを分けてもいいのですが、その場合も「クラスの先頭部分とファイル名が一致するようにする」というルールは維持します。
例えば.main-xxxx
というクラスが非常に多くなって_main.scss
が肥大化し、メンテしづらくなってきたとして、.main-content-
で始まるものを別ファイルに切り出したら、そのファイルは_main-content.scss
にします。
こうすることで、クラス名を見た瞬間にそれがどのファイルに書かれているのかがわかるようになり、開発効率が上がります。
同時に他のファイルに書かれたクラスと同じクラスをうっかり指定して上書きしてしまうような事故も防げます。
グローバルなクラスは必ず.g-
で始める
サイト全体で使うようなスタイル(たとえばボタンやform要素)は、全て.g-
で始まるクラスを使ってスタイル指定します。で、当然、_g.scss
に書きます。
/* サイト全体共通で使うボタンのスタイル */
.g-btn{ background:$g_color_brand; }
/* サイト全体共通で使うinput type="text" の要素のスタイル */
.g-input-text{ font-size:1rem; }
例.g-
が頭についたクラスはサイト全体で使われているということになるので、スタイルを変更する時には細心の注意が必要です。
クラスのネストは2階層まで
クラスのネストは基本的に2階層までです。
Sassだと深いネストなど楽に書けるのでついついやってしまいますがよほどの理由がない限り避けます。
.my-parent .my-child .my-element{ ... }
BAD.my-parent{ ... }
.my-child{ ... }
.my-parent-altenate{
.my-child{ ... }
}
GOODまた、別ファイルで定義されているクラスをネストして上書きすることもできるだけ避けます。
/* _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{ ... }
}
といった感じで、同じファイル内に定義されたクラス同士でネストさせる場合です。
それ以外のネストはできる限り避けます。
クラスをネストさせて多く重ねると詳細度が上がり、他の部分でそれを上書きするスタイルの定義が難しくなるためです。
@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; }
BADJavascriptとCSSの連携については、後述の「.mode-」のついたクラスでコントロールします。
Javascriptで使うIDは「x」で始めたcamelCaseとし、CSS側でそのIDは絶対に使わない
jsでのDOM操作のためにIDを割り当てる場合はid="xSomeElement"
というようにxから始まるcamelCaseで指定します。
CSS側ではこのIDに対してスタイルを当てるようなことはしてはいけません(まあ、そもそもIDは使ってはいけない事になってますが…)
JavascriptとCSSで連携する場合は.mode-
というクラスを通して行う
Javascriptから要素の表示非表示や見た目など、スタイルに関わる部分を変更したい場合は、.mode-
が頭についたクラスをつけたり外したりすることで行います。
Javascriptでのアニメーションは極力避け、できる限りCSSのtransitionやanimationで行います。
Sass
Sassの変数名はスネークケースで書く
ハイフンは使わず、$some_sass_vars
といったような、アンダースコア区切り+小文字のスネークケースで変数を定義します。
$base-margin: 12px;
$basePadding: 12px;
BAD$base_margin: 12px;
$base_padding: 12px;
BADハイフンを使わないのは、クラス名と区別をつけやすくすることと、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元のスタイルを変更した時に影響する範囲が見えず、意図しない部分に影響が出たりするのでできる限り避けます。
代わりに、
- 同じスタイルならできるだけ同じクラス名を割り振る
- 似たスタイルならクラスを複数振って上書きして調整する
- extendsしたいようなクラスは
.g-
のクラスとして定義して、ネストさせる
のを推奨です。
@extend
を活用したSASSライブラリなどを使う場合は除きます。
@mixin
も時に避ける
何かと便利なので使ったりしますが、@mixin
も時にちょっと避け気味にします。
mixinを使って似たような定義をたくさん作るなら、それを一つのclassにしてカスケードしてオーバーライドしたほうがいい場合も多いからです。
レスポンシブ対応はmixinで行う
ここはまだ練ってるところです。
今のところ以下のようなコードでやってます。
_mixins.scss※もっとスマートにわかりやすく書ける方法があれば知りたい
その他
BEMなどを使わない理由
BEMは、画面設計がしっかりできていて、CSSの設計に時間がかけられる場合はよいですが、だいたい自分の作るようなものは日々変化の多いものなので、
- ルールとしてやや複雑すぎる
- っていうかどれがBlockでどれがElementでどれがModifierだとかあれこれ余計な事を考えたくない
- 一つのモジュールのつもりで書いていたものの中のパーツをモジュールとして切り出したくなるとかいった変更をしたくなった時にストレス
といった理由で採用していません。