デザイナー・バックエンドの方もすぐに実践出来る!フロントエンド設計(CSS設計)のコツ
小原正大
こんにちは、2015年新卒の小原(こはら)です。フロントエンドを担当しています。
先日まで新規サービスの開発にジョインしてフロントエンドの設計・実装を行っていました。その時のことを振り返りながら、簡単に行えるフロントエンドコーディングの設計についてまとめようと思います。
柔軟性の高いフロントエンド開発の設計とは
どのようなサービス開発についても、仕様がはっきり決めきれなかったり今後の機能追加・変更が生じる可能性があり、ビジネス上の発想と同様に開発にも柔軟性が求められます。特に変更の起きやすいフロントエンドはなおさらでしょう。
フロントエンド開発における柔軟性とは、インターフェースの変更に対してどれだけ効率的・継続的にアップデートに耐えられるかと言えます。
では、どんな変更に耐えられればいいの?
インターフェースの変更と言っても「ちょっとこのボタンの色と大きさ変えて」とか「このコンテンツもっと上にして目立たせたいんだけど」など様々な種類があります。様々な修正は雑多に見えますが「機能の配置」に対する変更と「機能の見た目」に対する変更の二つに分割できます。
「機能の配置」と「機能の見た目」に分割
この2つを分離して開発することが効率的なアジャイルサイクルを生むと考えています。リーンやデザイン思考などからサービスに対して継続的にテスト・改善を加えていく場合、ユーザーシナリオ(機能に触れるストーリー → 機能配置)や、印象喚起(見た目が生み出す感情操作 → 機能の見た目)を独立させて変更することも多くなると思います。ここで「機能の配置」と「機能の見た目」の要素を分離した開発を行うと、一方を変えた際にもう一方にバグが生じることがなくなります(見た目の変更に伴うレイアウト崩れなど)。これによりアップデート対応速度が高く効率的に開発ができます。また機能のコンポーネントを積み木のように組み立ててサイトを構築できるので、気軽にいろいろなレイアウトパターンを試すことができます。
つまり、「機能の配置」と「機能の見た目」を意図的に分離した設計でフロントエンド開発を行えばサービス改善のための柔軟性を備えた開発ができると言えます。さらにこれはとても簡単です。
これだけ意識すればフロントエンドのことがよくわからなくても柔軟性のある良いコーディングに近づきます。
「機能の配置」と「機能の見た目」を分離した開発のやり方
前置きが長くなってしまいましたが、どのようにフロントエンド開発を行っていくか具体的に説明します。
方針として、DOM構造やCSSに関して「機能の配置」と「機能の見た目」を分離するというルールを敷いたコーディングになります。
※ 詳細な規約としてはSMACSS的なファイル構成とレイアウトの命名を行って、モジュールに対してはBEMチックな命名を行いました。
「機能の見た目」についてのコーディング方法
はじめに「機能の見た目」についてのコーディングですがリキッドデザイン的に開発を行いました。ここでのリキッドデザインとは外枠に依存した縦横サイズなどが可変な実装のことを意味しています。以下のような実装になります。
// 例1 左デザイン
<div class="item">
// itemの見た目に関するcssクラスに全てitemの命名をつける
<div class="item__movie">...</div>
<div class="item__body">
<div class="item__body__title">...</div>
<div class="item__body__prof">
// itemにprofを組み込んでいる
// 同様にprofの見た目に関するcssクラスに全てprofの命名をつける
<div class="prof">
<div class="prof__user">
<div class="prof__user__img"></div>
<div class="prof__user__inf"></div>
</div>
</div>
</div>
<div class="item__body__tag">...</div>
</div>
<div class="underline"></div>
</div>
/** 大枠の.itemは気をつけて設計 **/
.item{
width: 100%; /**「itemの配置」のcssに横幅指定を任せるために横幅を100%指定する **/
/** float: left; 悪い例 「itemの配置」用のcssは記述しない **/
/** margin: 10px; 悪い例 「itemの配置」用のcssは記述しない **/
/** 以下は見た目のcss **/
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-box-shadow: 0px 1px 3px rgba(51, 51, 51, 0.3);
-moz-box-shadow: 0px 1px 3px rgba(51, 51, 51, 0.3);
box-shadow: 0px 1px 3px rgba(51, 51, 51, 0.3);
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
}
/** item外でcss干渉を起こさないようにするため入れ子 **/
/** またitemの子要素であることを明示的に命名するために__を使用 **/
.item .item__body{
/** 自由にcssを展開する **/
...
}
.item .item__body .item__body__title{
/** 自由にcssを展開する **/
..
}
// 例2 右デザイン
<div class="nav">
<div class="nav__title--l">...</div>
<div class="nav__select">
<div class="nav__select__child">...</div>
<div class="nav__select__child">...</div>
<div class="nav__select__child">...</div>
</div>
<div class="nav__title--s">...</div>
<div class="nav__title--s">...</div>
<div class="nav__title--s">...</div>
</div>
/** 大枠の.navは気をつけて設計 **/
.nav{
/**「navの配置」のcssに横幅指定を任せるために縦横幅を100%指定する **/
width: 100%;
height: 100%;
/** float, marginなど、レイアウトに関するcssは記述しない **/
/** 以下は見た目のcss **/
-webkit-box-shadow: 1px 0px 3px rgba(153, 153, 153, 0.5);
-moz-box-shadow: 1px 0px 3px rgba(153, 153, 153, 0.5);
box-shadow: 1px 0px 3px rgba(153, 153, 153, 0.5);
position: relative;
color: #e9e8e8;
background-color: #253038;
}
/** nav外でcss干渉を起こさないようにする **/
.nav .nav__title{
/** 自由にcssを展開する **/
...
}
.nav .nav__title.nav__title--l{
/** 自由にcssを展開する **/
...
}
.nav .nav__select{
/** 自由にcssを展開する **/
..
}
何をしている?
class="item"
や class="nav"
以下に、任意のコンポーネントについての「機能の見た目」の責務を持たせるようにコーディングしています。class="item__body
"などclass="item"
内部のcss設計も工夫はできるのですが、ひとまずは親であるclass="item"
やclass="nav"
に「機能の配置」に関するcssが記述されていない状態であれば問題ありません。
これにより、class="item"
やclass="nav"
を「機能の見た目」として独立させています。
class="nav__title--l"
など「__」や「--」を含むの命名はBEM記法に基づいてコーディングしています。ここでの役割はただの命名規約で例えばclass="item"
外でのcss干渉を明示的に防ぐために使用しています。
「機能の配置」についてのコーディング方法
次に「機能の配置」についてのコーディングですが、それぞれのデザインコンポーネントを配置するための箱を用意していきます。以下のような実装になります。
<html>
<head>...</head>
<body>
<div class="l-wrap">
<div class="l-main">
<div class="l-header"></div>
<div class="l-height-offset"></div>
<div class="l-side"></div>
<div class="l-cont">
<div class="l-cont__body"></div>
</div>
</div>
</div>
</body>
</html>
/** レイアウトを表すコードに"l-"のプレフィックスをつける **/
/** background, color, borderなどなど、見た目に関するcssは記述しない **/
/** 大きさ、配置だけを定義する透明な箱を作っていくイメージ **/
.l-wrap {
width: 100%;
height: 100%;
/** background-color: white; のような見た目を作るコードを記述しない **/
}
.l-main {
width: 100%;
min-height: 100%;
vertical-align: top;
}
/** 見た目を表すコードを書く場合はクラスを分離する **/
.main {
background-color: #fbfbfc;
}
.l-header {
position: fixed;
z-index: 100;
top: 0;
left: 0;
width: 100%;
height: 48px;
}
.l-height-offset {
height: 48px;
}
.l-side{
position: fixed;
z-index: 99;
top: 48px;
width: 230px;
height: 100%;
max-height: 100%;
}
.l-cont{
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
padding-left: 230px;
margin: 0 auto;
}
.l-cont__body {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
max-width: 1064px;
min-height: 80%;
padding: 48px 28px;
margin: 0 auto;
}
何をしている?
レイアウトを表すコードを記述して「機能の配置」を構成しています。その際「機能の見た目」に関するcssは排除します。イメージとしては大きさ、配置だけを定義する透明な箱を作っていくようにコーディングしています。
class="l-cont"
のように"l-"のプレフィックスをつけていますが、これはレイアウトを構成するcssであること明示化するためにSMACSS的な記法を真似しています。BEM記法を利用した時と同じでここでの役割はただの命名規約で「機能の配置」を明示的に独立させるために利用したシンボルのようなものです。
「機能の配置」に「機能の見た目」を当てはめたもの
これらの「機能の配置」に「機能の見た目」を当てはめたものが以下です。
カンタン作業!
「機能の見た目」を積み木のように「機能の配置」に当てはめるだけの作業です。
この二つを分離するだけで、見た目の修正をするときに配置崩れが起きたりすることはなくなり、機能追加・削除があったときも、積み木を引き足しするだけでの作業を行うだけです。
最後にもう一度
「機能の配置」と「機能の見た目」をわけるというコツを抑えるだけで、柔軟なコードを書けるようになります
もしデザイナー・バックエンドなどの非フロントエンドの方で「サイト作りたいけど人手が足りない!ちょ、君、なんとかコーディングしてよ!!」的なシチュエーションになってフロントエンドのコーディングをする時はぜひお試しください。コーディングに対して少しでも苦手意識がなくなり、自信をもってコードを書いていけるようになれば幸いです。今後ともよろしくお願い致します。