CSSとはレイアウトとコンポーネントのデザインをするもの。
src/component/
次にはそれぞれのコンポーネントに対するCSSを置くsrc/css/
にはベースや変数など全体として適応されるものを置く
コンポーネントに関連するCSSはコンポーネント単位でJavaScriptと同居するので同じルールが適応される。
- src/component/container/
- ページから見たレイアウトを扱える
- Containerコンポーネントのレイアウト
- src/component/project/
- プロジェクトコンポーネントに対するスタイル
- src/component/ui-kit/
- ui-kitに対するスタイル
コンポーネント以外のCSSは src/css
に配置する。
- src/css/base.css
- 指定要素や
*
に対して適応するベースのCSS - normalize.cssのようなもの
- 指定要素や
- src/css/*.css
- グローバルなCSS Custom Property変数
- CSS Custom Property変数は上書き禁止(PostCSSでは正しく依存を解決できないため)
すべてのCSSは src/index.css
から postcss-easy-import
のワイルドカードで読み込まれる。
CSSの読み込みについては次の点に注意する。
- Base CSSは最初に読み込まれる
- それ以外のCSSは読み込み順序に依存してはいけない
- 各CSSファイルを読み込むために明示的な
@import "path/to/file.css"
を書く必要はない- ワイルドカードで読み込まれるため
- 各コンポーネントは
component/分類/<ComponentName>/<ComponentName>.css
のように配置するComponentName
は大文字開始のキャメルケール<ComponentName>.css
にはそのコンポーネントと子コンポーネント(<ComponentName>-<childName>
)を含んでよい- 対となるJavaScript(React)に書かれていないクラスはできるだけ扱わない(コンポーネント間の独立性を保つ)
- 各コンポーネントのStateは
分類/<ComponentName>/<ComponentName>.is-<stateName>.css
のように配置する- StateごとにCSSファイルを分ける
- 各コンポーネントのディレクトリの中にはJavaScriptとCSSと同居して存在する
合わせて読む: ComponentのREADME
命名規則はSUIT CSSの規約に準拠する。
.コンポーネント名 {}
.コンポーネント名-子要素名 {}
.コンポーネント名.is-ステート名 {}
.コンポーネント名--modifier {}
ただしSUIT CSSのライブラリなどはそのまま使わなくてもよい。
- コンポーネント(Container/Project/ui-kit)はそのコンポーネントより上の要素/クラスのスタイルを扱わない
- 上の要素が下の要素のスタイルを扱うのは許容されるが、避けられる場合は避けるようにする
- 例) containerコンポーネントがprojectコンポーネントに対して
width
を設定する
- 例) containerコンポーネントがprojectコンポーネントに対して
例) MyComponentのケース。
MyComponent/MyComponent.js
というコンポーネントがあった場合に。
import React from "react";
export default class MyComponent extends React.Component {
render() {
return <div className="MyComponent">
<h1 className="MyComponent-title">{this.props.title}</h1>
</div>;
}
}
CSSは次のような形で書く。
MyComponent/MyComponent.css
:
.MyComponent {
}
.MyComponent-title {
}
MyComponentにstateがある場合は、SUIT CSSの規約にもとづき is-*
というクラスが追加される。
次の例はis-active
というstateが追加されているコンポーネントを示したもの。
<div className="MyComponent is-active">
<h1 className="MyComponent-title">{this.props.title}</h1>
</div>
このis-active
stateに対するCSSは、MyComponent/MyComponent.css
とは別ファイルとして作成する。
コンポーネント名.is-ステート名.css
という命名規則で作成し、stateに関するCSSのみを記述する。
MyComponent/MyComponent.is-active.css
:
MyComponent.is-active {
/* is-active の時のスタイル */
}
stateを別ファイルにすることで、 コンポーネントディレクトリを見た際に、そのコンポーネントのstateが一覧できることを目的にしている。
- Project Componentはそのコンポーネントの内側のスタイルを当てる
- レイアウトを意識したmarginやpadding、heightなどのスタイルは当てない
min-width
などのコンポーネントとして保証できるスタイルは問題ない
- ContainerはProject Componentを使うため、Containerから見たProjectのスタイルを当ててもよい
- あるXContainerにあるYProjectComponentの
width
やheight
などをレイアウトを指定してもよい
つまり、次のようにある.Container
の下の.ProjectComponent
というスタイルを、
Container.css
に書いてもよい。
.Container .ProjectComponent {
}
CSSの詳細度やSUIT CSSの規約を考えると、
次のようにProject Componentは外からclassName
を受け取れるようにするとよりよい。
MyComponent
:
import React from "react";
// https://github.com/JedWatson/classnames
import classNames from "classnames";
export default class MyComponent extends React.Component {
render() {
const classNames = classNames("MyComponent", this.props.className);
return <div className={classNames}>
<h1 className="MyComponent-title">{this.props.title}</h1>
</div>;
}
}
Container
:
import React from "react";
import MyComponent from "./MyComponent";
export default class Container extends React.Component {
render() {
return <div className="Container">
<MyComponent className="Container-MyComponent"/>
</div>;
}
}
こうすることで、先ほどの.Container
の下の.ProjectComponent
というスタイルは、
次のようにContainer.css
へ書ける。
.Container-MyComponent{
}
PostCSSを使い、CSS Custom Property(--variable: <値>;
)を変数として利用できる。
CSS Custom Propertyの仕様的には、変数の上書きはできるが読み込み順序に依存するため、
基本的に変数は再定義しないでグローバルな定数として扱う。
そのため、各コンポーネントに変数を宣言するのではなく、src/css/
次に宣言してコンポーネントではそれを利用する。
CSS Custom Propertyの仕様は下記を参照する。
- CSS Custom Properties for Cascading Variables Module Level 1
- CSS カスケード変数のためのカスタムプロパティ — CSS Custom Properties for Cascading Variables Module Level 1 (日本語訳)
--<変数名> : <値>:
という形で変数を定義できる。
変数名の名前の区切り文字には--
を使う。
--<種類>--<名前>
PostCSSで扱えるCSS Custom Propertyの変数はグローバル変数である。 そのため、グローバルに必要な変数とコンポーネントに紐づく変数を命名規則で分離する。
グローバルな変数はページ全体から見た時に、認識として共通であるものをまとめるために利用する。 現在が同じ色だからという理由で、1つの変数を使いまわすと、 変更する際の変更箇所が増えてしまいまとめた意味がなくなってしまうことに注意する。
- 色
- フォント
z-index
- コンポーネント間の幅(できればコンポーネントに紐づくものとして管理したい)
- 幅や高さ
- など
変数を使わなくても問題ない部分を無理やり変数にまとめようとしない。 (あくまでグローバル変数なので、グローバル変数を増やしすぎるのも逆に問題が起きやすいため)
MixinはCSS @apply Ruleを使い実現する。
次のように書くことでSassなどで見られるMixinを実現できる。
:root {
--mixin--inline-block: {
display: inline-block;
vertical-align: top;
};
}
.Toolbar {
@apply --mixin--inline-block;
}
- CSS @apply Rule
- 現在ドラフトの仕様となっている
- そのためIDEなどのエディタではまだサポートされていないため構文エラーとして扱われる場合がある
Mixinとなる変数名は、--mixin--
で始まる変数名を使う。
:root {
--mixin--inline-block: {
display: inline-block;
vertical-align: top;
};
}
コンポーネントの要素には一意なコンポーネント名があるため、それに準拠した変数名を使う。
--<ComponentName>--<PropertyName>: 値:
という形式を利用する。
例): ComponentName-childName
の width
に対する変数。
.ComponentName-childName {
width: var(ComponentName-childName--width, 100px);
}
z-index
の値は z-index.css に定義されているベースの値を各コンポーネントで利用する。
クラス間で前後関係が必要な場合は、calc
を使い相対値で指定する。
.ComponentB {
z-index: var(--z-index--default)
}
/* Bより前に表示する */
.ComponentA {
z-index: calc(var(--z-index--default) + 1)
}