Misocaという会社でなんかしてる @merotan ともうします。
最近仕事でとある機能のUIリニューアルをおこなうことがありまして、僕はどうしてもPostCSSを使いたかったのと、現行のクソみたいになっているCSSからなんとしてでも脱却したかったので、どうすればクソなことにならずいい感じにCSSを書くことができるか考えて実践してみた結果を書いていこうと思います。
影響を受けているもの
参考・影響を受けているものとしてFLOCSS、BEM、AtomicDesignなどがあります。
意識はしてないものの何かでみてあーこれ良いなと思ったものもあるかもです。
命名規則
命名規則はBEMです。(BEMの説明はここではしないので、上のリンクから確認していただければと)
ですが、Modifierはカスタムデータ属性を使用します。
またModifier
はカスタムデータ属性を活用します。
こうすることで無理にクラス名で状態等を表現することがなくなり、HTML
でのクラス名が短くなり非常に読みやすくなります。
詳しくは
CSS設計の類はもっとカスタムデータ属性を活用するべきでは
か
BEMのModifierはclassで書くのやめませんか?
で。
使用ツール
PostCSSを使用します。
将来的に実装されるであろう機能がPostCSS
のプラグインとして提供されているので保守性が高いと思います。
主に使うプラグインがこれらになります。
詳細はここでは説明しませんので、Githubで確認していただければと思います。
基本ルール
基本的にHTMLタグに対して複数のクラスは付けないようにします。
1タグ1クラスにします。
ファイル構成
ファイル構成は以下のようにします。
src/stylesheets/
|-- main.css
|
|-- foundation/
| |-- index.css
| |-- reset.css
| `-- base.css
|
|-- variables/
| |-- index.css
| |-- layout.css
| `-- color.css
|
|-- units/
| |-- index.css
| |-- text.css
| |-- color-palette.css
: :
|
|-- parts/
| |-- index.css
| |-- button.css
| |-- message-ballon.css
: :
|
|-- components/
| |-- index.css
| |-- header.css
| |-- member-list.css
| |-- modal
| | |-- index.css
| | |-- confirm-window.css
| | |-- alert-window.css
: :
|
|-- layouts/
| |-- index.css
| |-- index-layout.css
| |-- edit-layout.css
: :
|
|-- utilities/
| |-- index.css
| |-- margin.css
| |-- padding.css
: :
main.css
はエントリーポイントです。
基本的には
@import 'foundation';
@import 'variables';
@import 'units';
@import 'parts';
@import 'components';
@import 'layouts';
@import 'utilities';
このように定義するだけになります。
また各ディレクトリのindex.css
では基本的には各ディレクトリのCSSファイルをインポートするようにします。
foundation
foundationでは主にReset.css
やNormalize.css
等のブラウザのデフォルトスタイルの初期化、アプリケーションのベースとなるスタイルを定義します。
アプリケーション全体の背景、フォントの設定等を行います。
variables
ここではアプリケーションで使われるグローバルな変数を定義します。
CSS Custom Propertiesを使い定義していきます。
プラグインとしてはpostcss-custom-propertiesです。
-
layout.css
にはアプリケーションのレイアウトのwidth
等の変数を定義します。 -
color.css
にはアプリケーションで使われる色を定義します。
:root {
--nav-width: 200px;
--content-width: 700px;
}
:root {
--text-default-color: #333;
--text-warning-color: red;
}
こんな感じ。
units
ここではアプリケーションの各 parts
/ component
を構成するのに必要なものを定義します。
例をあげると、文字の大きさ(font-size
)と文字の太さ(font-weight
)の組み合わせや、背景色(background-color
)と文字色(color
)の組み合わせ、
のようなアプリケーションの構成要素として基本的なモノを定義していきます。
CSS @apply Ruleを使用します。
プラグインとしてはpostcss-applyです。
:root {
--default-text: {
font-size: 14px;
font-weight: normal;
line-height: normal;
}
}
:root {
--main-color-set: {
color: white;
background-color: var(--main-color);
}
--warning-color-set: {
color: white;
background-color: var(--warning-color);
}
}
:root {
--rounded-rectangle: {
border-radius: 4px;
}
}
以上のように書いていきます。
parts
ここではアプリケーションに必要最小限の構成物を定義します。
ボタンや、メッセージバルーン、タブ、テキストフィールドといった汎用的なモノを定義します。
基本的には子要素(BEMでいうエレメントですね)を作らないようにします。
必要最小限の構成物なので、複雑なものは作らないようにします。
.button {
@apply --main-color-set;
@apply --default-text;
@apply --rounded-rectangle;
&[data-size="large"] {
width: 200px;
height: 50px;
}
&[data-size="small"] {
width: 20px;
height: 20px;
}
}
このように基本的にはunit
を組み合わせて作っていきます。
ですが基本的にはなので、ここにスタイルを書いてはだめということではありません。
こうすることで、パット見でどういうスタイルなのかがわかりやすくなります。
上の例だと、**「色はアプリのメインの色で、文字はデフォルトのもので、角丸な四角い、ボタン」**ということが、詳細をみなくてもわかるようになります。
components
ここではアプリケーション内で使う大きい構成物を定義します。
components
は他のcomponents
やparts
を子要素として持つ場合があります。
components
内でcomponents
やparts
を子要素として持つ場合は、
hogeArea
(このhoge
は基本的にはcomponents
名やparts
名にしますが、大まかに左と右で分けたい等ある場合は、leftArea
、rightArea
とすることもあります。)をつくってその中に、components
やparts
を格納します。
.header {
@apply --clearfix;
height: var(--app-header-height);
&_logoArea {
float: left;
}
&_loginButtonArea {
float: right;
}
}
<header class="header">
<div class="header_logoArea">
<img class="logo" src="logo.png" />
</div>
<div class="header_loginButtonArea">
<button class="button">ログイン</button>
</div>
</header>
このような感じです。
こうすることで、他のcomponents
やparts
に対してスタイルの上書きを行わないようにします。
また、似たようなcomponents
(例えば確認ダイアログとアラートダイアログは似たような見た目かと思います)はディレクトリを切るようにします。
そのディレクトリのindex.css
にそのコンポーネント共通のunits
やvariables
、共通の親components
等を切り出します。
こうすることで、似たようなコンポーネントだからといってむやみにunits
として切り出してしまうことを抑制でき、かつ似たcomponents
をまとめることができます。
layouts
ここでは各component
をどこに配置するかを定義します。
大枠のワイヤーフレームを書くものです。
基本的にはfloat
やflexbox
、position
を利用してレイアウトを行っていきます。
.applicationLayout {
display: flex;
flex-direction: row;
&_navArea {
order: 1;
width: var(--application-nav-width);
}
&_contentArea {
order: 2;
width: var(--application-content-width);
min-width: var(--application-content-min-width);
}
}
命名規則としてhogeLayout
のように後ろにLayout
をつけます。
また、子要素はすべてhogeArea
(components
のと同様に)のように後ろにArea
をつけます。
utilities
ここではある特定の一箇所でのみスタイルを当てたいという場合が発生した時に使うスタイルを定義します。
例えば説明文中にそこでしか使わない、特別なmargin
が必要な場合等に使います。
命名規則は特殊なものとわかりやすくするために、
u-hoge
のように最初に**u-
つけるようにします。
またそのスタイルを優先(強制)させるために!important
**を必ずつけるようにします。
.u-description-margin-bottom {
margin-bottom: 10px !important;
}
使ってみた感想
自分で考えたこともあるのですが、非常にやりやすかったです。
特にhogeArea
のお陰でスタイルの上書きをすることがなくレイアウトできたのがよかったなぁとおもいました。
またunits
は良かったです。parts
のところにも書いたのですが、人が書いたCSSでも詳細を見ることなく、@apply
のところを読むだけで「こういう見た目になるんだろうな」というのがすぐひと目でわかるのがとても良かったです。
とはいえ、どの程度のものをunits
に切り出すか、parts
とするかというのが難しくて悩むことが多かったです。
でも多分そのへんはどの設計でも難しいのかなとも思ったりしたり…。
また、Layouts
の恩恵があまりうけれずこれいるのかなぁ…とおもったりしたりしました…。
まだまだ改善点がたくさんあるだろうなとつよく思い、今後も改善していこうと思いました。
世の中には色々CSSの設計思想があってどれも良いものだと思いますが、
皆さんのやりやすいやり方を見つけたり考えられたりできるといいなと思います。
これが皆さんのなにか参考になるといいなぁと思います。