CSSの保守性と見通しを高めて、プロジェクトに対するモチベーションを維持するためにやってることをまとめてみました。
主にCSSを保守するのがめんどくさいという事に対する愚痴が書いてあります。完全な持論ですので「そんなの絶対おかしいよ!」と思う事、あると思います。つっこみお待ちしております。
簡単なまとめ
- クラスで切るんじゃなくてメタ言語のMixin(Function)で切る
- よく使う値は変数で管理する
- Bootstrapを逃げ道にするのはやめよう
長いけどこれだけです。以下は時間がある人だけ読んでください。
前提
-
Stylusというメタ言語を使用しています。Rubyistは適宜
SCSS
に読み替えるなどしてください、文法は殆ど同じです。 - StylusはLESSと違ってサーバサイドでのみコンパイル可能なメタ言語なので、どんな非効率なコードだろうと気にする必要ないと思ってます。
- ブラウザのCSSレンダリング速度はプロトタイピング中は気にしなくていいかなって思ってます。
- クラスベースのCSSをdisってるわけじゃないです。
- HTMLはjadeというメタ言語を使っています
わたしがまずいと思ってること
最近のイケてるサービスやBootstrapなどのCSSフレームワークでは、主にクラスベースでスタイルを切り分けてます。あれはHTML4.*とCSS2.*における完成系です、最初からあそこに辿り着こうと思ったらプロジェクトが崩壊します。
クラスベースのスタイライズを行うと、HTMLとCSSが密結合になります。スタイルの適応や修正にHTMLをいじる必要が出てきます。HTMLを過度に編集するとJSが不審な挙動を起こし始めることもよくあります。そして、JSのためにHTMLを編集するとそれに伴ってCSSも編集する必要に迫られることすらあります。
つまり、途中でスタイルを見直すと「CSSを編集⇄HTMLを編集⇆JSを編集」というコンボがキマり、結局全てのファイルを弄るハメになる場面が多々あります。スタイルを変更するのにロジックもいじらないといけないなんて変ですね。クソ食らえです。
結局、後に残るのは「全てを捨ててスマートなプロダクトをゼロから再実装したい」という欲求です。
個人や少人数など、足が軽い状態で実装していると「ゼロから再実装したくなる欲求」を抑制することは非常に困難です。加えて、そのような欲求に苛まれた際にもう引き返せないラインに到達していると、実装意欲の急激な低下を招き、結果としてプロジェクト放棄の原因となります。オナ禁っぽいですね。
これらを防ぐためにも、プロトタイピングにおいて「スタイル調整に伴うViewの変更」は不要とされるべきです。HTMLとCSSは疎結合であって欲しいというのが私の願いで、スタイルのことはスタイルの中で完結するべきなんです。
またプロダクション環境であっても、Viewの変更はユーザからキャッシュを奪うことになるので非効率なんじゃないかなって思います。
長い繰り返しコードはFunctionにして外部化する
微妙に値を変えながら繰り返して使用されるテンプレートはFunction
にします。
よくない例
例えば「マージン5pxの合計60x60pxのオブジェクトにviewからbackground-imageを指定して、要素の短辺を満たす最大サイズにfitさせたい」という場合、こんな風に書くと思います。
// html
.picture(style='background-image:url(#{pict})')
// css
.picutre
margin 5px
width 50px
height 50px
background-color transparent
background-size contain
background-repeat no-repeat
background-position 50% 50%
クラスベース信者はすぐにこうしたがります。
// html
.picture.background-contain(style='background-image:url(#{pict})')
// css
.picture
margin 5px
width 50px
height 50px
.background-contain
background-color transparent
background-size contain
background-repeat no-repeat
background-position 50% 50%
後から他のスタイルでbackground-positon
やmargin
を弄る必要が出るとこうします。
// html
.picture.background-contain(style='background-image:url(#{pict})')
.image.background-contain.background-position-topleft(style='background-image:url(#{img})')
// css
.picture
margin 5px
width 50px
height 50px
.image
margin 10px
width 20px
height 20px
.background-contain
background-color transparent
background-size contain
background-repeat no-repeat
background-position 50% 50%
.background-position-topleft
background-position 0 0 !important
何れもViewを弄る必要性が出てきます。もしmargin
やwidth
やheight
もクラス化したい気分になっていたらそれはもう終わりの始まりです。
これではダメです。
よい例
// html
.picture(style='background-image:url(#{pict})')
.image(style='background-image:url(#{img})')
// css
background_fit(bgsize, leftposition = 50%, rightposition = 50%)
background-color transparent
background-size bgsize
background-repeat no-repeat
background-position leftposition rightposition
.picture
margin 5px
width 60px
height 60px
background_fit contain
.image
margin 10px
width 20px
height 20px
background_fit contain 0 0
background_fit
の定義部が長くて全体の見通しを悪化させるので外部化します。
// html
.picture(style='background-image:url(#{pict})')
.image(style='background-image:url(#{img})')
// css
@import 'background_fit'
.picture
margin 5px
width 60px
height 60px
background_fit contain
.image
margin 10px
width 20px
height 20px
background_fit contain 0 0
もしmargin
やwidth
やheight
も自動化したかったらこんな定義もあり得ます。
// css
background_fit_box(margin, boxsize, bgsize, leftposition = 50%, rightposition = 50%)
margin margin
width w = (boxsize - margin*2)
height w
background-color transparent
background-size bgsize
background-repeat no-repeat
background-position leftposition rightposition
.picture
background_fit_box 5px 60px contain
スマートです。
共通の色など、よく使う値は変数で管理する
stylusなどのメタ言語に乗っかってもせいぜい{}:;
の省略とインデント程度しか使わず、MixinやVariableやConditionを活用しないし、むしろ活用しない方が実装速度が早いという人はいると思います。
でも、なんでそれが実装されてるのか?という点から考えれば自明の便利さがあります。
例えば、これをカラーベースにしてサイトを組もうと思い立ちます。
html, body
color #3D3936
background #ECE8DF
#header
color #ECE8DF
background #3D3936
#article
background #FCFDFD
&:hover
background #F1F1F2
後から見たら「どこに」「どの色が」「どういう方針で」使われたのか全くわからないし、全部でどれだけの色数があるのかもわからない。
Typoがあってもきっと気づかないし、スキーマ変更に全文リプレイスを使用していると、その煩雑さから途中で「これでいいや(・ω・`)」という気持ちになってしまいます。
なので、こうします。
whitecolor = #FCFDFD
whitecolor_highlight = #F1F1F2
basecolor = #ECE8DF
basecolor_highlight = #CEC9C0
maincolor = #3D3936
maincolor_highlight = #1E1A17
accentcolor = #24B9EC
accentcolor_highlight = #089ACE
html, body
color maincolor
background basecolor
#header
color basecolor
background maincolor
#article
background whitecolor
&:hover
background whitecolor_highlight
header
だけ色が反転している、hover
した時にのみ*_highlight
を使う、等の情報がわかりやすくなります。
「コードから色の意味がわかるようにする」というのは有効な手段だと思います。レンダリングされたUIが意図した通りに動作・発色するかを効率的にテストする手法が無い(と思ってるけどあるのかな)ので、実際にhover
して間違った色を使ってないかチェックする手間は最後だけで済みます。
スキーマ変更時も変数を書き換えればよいだけなので、プロトタイピングも捗りますね。
もっと厳密な制約を課したい場合は、関数化するのもありです。
color_scheme(schema)
if schema is 'regular'
color maincolor
background basecolor
if schema is 'inverse'
color basecolor
background maincolor
if schema is 'article'
color maincolor
background whitecolor
&:hover // これをここに書くべきかどうかは要判断
background whitecolor_highlight
html, body
color_schema 'regular'
#header
color_schema 'inverse'
#article
color_schema 'article'
また、*_highlight
カラーが元のカラーから一定の法則で生成できるのならば、下記のように色を定義することも可能です。これはstylusの機能なので他にあるかは知りません、LESSではありました。
whitecolor = #FCFDFD
whitecolor_highlight = darken(whitecolor, 10)
basecolor = #ECE8DF
basecolor_highlight = darken(basecolor, 10)
maincolor = #3D3936
maincolor_highlight = darken(maincolor, 10)
accentcolor = #24B9EC
accentcolor_highlight = darken(accentcolor, 10)
共通する色や値の管理はCSSコーダーに取って結構な課題だと思います。何らかの方法を使ってスマートに解決しましょう。
最後に
みんながBootstrapに逃げたがるのって、うまいCSSの書き方メソッドを持ってなくてViewを浸食してぐちゃぐちゃにしちゃった経験に起因してるのかなって思ってます。保守性の高いCSSって語られる機会があまりないし、ぐぐってもSCSS万歳みたいな記事しか出てこなかった。
デザインが画一化するとインターネットがつまらなくなるので、こういう感じでCSSの保守性を高める自分なりのメソッドを見つけて、独自のCSSを楽しく書く人が増えればいいなって思います。
あと、CSSのレンダリング速度がどうしても気になる人は、「プロダクトが完成してから」リファクタリングを行いましょう。
あと、メタ言語にstylus
を採用したら光属性ライブラリnib
はチェックしましょう。global-reset()
とか、border-radius
・linear-gradient()
といった先進的実装をベンダープレフィックスで自動展開とか、clearfix
の機能なんかを拡張してくれます。
以上です。インターネットの平和を願って。やみのま。