- .sassより.scss
- 変数で変更をしやすく
- パーシャルと@importでモジュールごとにファイルを管理する
- よく使うスタイルはデフォルトで置いておく
- CSSの構成案を導入する
- ネストは最小限に、検索しやすく
- ブレイクポイントはMapと@mixinで管理する
- レスポンシブに対応したクラスをつくる@mixin
Sassはインデントで階層構造を示すSASS記法とCSSに近いSCSS記法の2つがあります。SASS記法はブレース(波括弧)とセミコロンを省略できるのでコードが簡潔になりますが、SCSS記法を使いましょう。
// SASS記法
a
color: blue
text-decoration: none
&:hover
color: red
// SCSS記法
a {
color: blue
text-decoration: none
&:hover {
color: red
}
}
インデントで構造を示す言語は使い慣れないと拒否反応が起きやすいです。SCSS記法はCSSの記法とほとんど同じなので、普通に読むことができると思います。
また、SCSS記法はCSSのコードをそのまま貼付けても動作します。SASS記法だと書き直す必要があります。そのうえ、BootstrapのようなCSSフレームワークや、jQueryのプラグインなどでも、SCSS記法のほうがよく使われています。
CSSには変数という機能を現段階で使用することはできません。「CSS Custom Properties」という機能も現段階ではChromeやFirefoxの最新版以外は対応していません。
- CSS Custom Properties for Cascading Variables Module Level 1
- Can I use... Support tables for HTML5, CSS3, etc
- 僕がネイティブな CSS 変数にわくわくする理由
ですが、CSSプリプロセッサー(CSSを作るためのツール)のひとつであるSassなら変数の機能を使用することができます。
以下の例ではブランドカラーを定義する変数$color-brand
と要素間のマージンのベースになる変数$base-spacing
をそれぞれ2回ずつ指定しています。
$color-brand: red !default;
$base-spacing: 1.7rem !default;
.heading {
margin-bottom: $base-spacing;
font-size: 2rem;
color: $color-brand;
}
.box {
margin-bottom: $base-spacing;
padding: 1em;
color: $color-brand;
}
変数を利用しないと、たった1つの共通パーツのデザイン変更で何箇所も変更しなければいけませんが、変数を使えば1箇所変更するだけで、すべての箇所を変更することができます。
// 値をredからblueに変更
$color-brand: blue !default;
// もしくは、変数を定義したファイル箇所より前に同じ変数名で定義
$color-brand: blue !default;
$color-brand: red !default;
Sassのファイル名は通常、module.scssのようにつけますが、_module.scssのように先頭にアンダースコアをつけると、そのファイルはコンパイル(CSSとして出力)をしてもCSSファイルとして個別に出力されなくなります。この機能をパーシャル(partial)と呼びます。
アンダースコアのついたSassファイルは、@import
を使用することで、アンダースコアのついていないSassファイルの中で呼び出すことができます。
// style.scssのなかの記述
// 同じ階層にある_module.scssをインポートする
@import "_module1.scss";
@import "_module2.scss";
// 使用しないファイルはSassのコメントをつける
@import "_module1.scss";
// @import "_module2.scss";
HTMLに複数のCSSファイルを読み込みたい場合はHTML側でインポートしていましたが、CSSファイルを出力する段階ですることができます。Sassでは機能ごとにファイルを分割するのが基本です。
パーシャルと@importで、どのファイルを出力するかを管理できるようになったので、よく使うスタイルをまとめたファイルをつくりましょう。例えば、font-family
やグリッドレイアウトなど。
// よく使うfont-familyをまとめています。
$font-sans-serif-1: "Helvetica Neue", Helvetica, "Hiragino Sans", "Hiragino Kaku Gothic ProN", Meiryo, sans-serif;
$font-sans-serif-2: "Helvetica Neue", Helvetica, "游ゴシック", YuGothic, "Hiragino Sans", "Hiragino Kaku Gothic ProN", Meiryo, sans-serif;
$font-serif-1: "Times New Roman", "Hiragino Mincho ProN", "HG明朝E", Meiryo, serif;
$font-serif-2: "Times New Roman", "游明朝", "YuMincho", "Hiragino Mincho ProN", "HG明朝E", Meiryo, serif;
// グリッドレイアウトのベーススタイルです。
.c-grid {
display: block;
margin: 0;
padding: 0;
font-size: 0;
list-style-type: none;
}
.c-grid__item {
display: inline-block;
width: 100%;
font-size: 1rem;
vertical-align: top;
}
ここまででファイルを作って、管理することができるようになりました。_font.scssや_grid.scssのようなファイルが散乱していませんか?ここでファイルを整理するためのルールをつくりましょう。
いちから作るより、FLOCCSやITCSS、SMACSSのような構成案をベースにしましょう。
個人的にはFLOCSSをベースするのがいいと考えています。FLOCSSの発案者が日本人の谷 拓樹さん(hiloki)なので、ドキュメントが日本語なこと、CSSに関するスライドをたくさんあげているので参考資料が多いことがおもな理由です。
CSS構成案をひととおり理解できていれば、どの構成案を使っても大きくは変わらないんじゃないかという印象です。どれも、影響範囲と詳細度を管理するためのツールです。
以下は僕が主に使っているディレクトリです。
- Foundation
- function
- variable
- mixin
- vendor(Normalize.css)
- base(プロジェクトにおける、基本的なベーススタイル)
- Layout(ヘッダーやフッターのような、ページを構成するコンテナブロック)
- Object(プロジェクトにおけるビジュアルパターン)
- component(多くのプロジェクトで横断的に再利用のできるような、小さな単位のモジュール)
- project(プロジェクト固有のパターンで、コンテンツを構成する要素)
- utility(いわゆる汎用クラスで、ほとんどの場合は単一のスタイル)
Sassはネストで親子関係などを示すことができるので、コーディングを楽にすることができます。
// Sass
.foo {
.bar {
color: red;
}
}
.foo {
&-bar {
color: red;
}
}
.foo {
&:before {
content: "";
}
}
/* CSS */
.foo .bar {
color: red;
}
.foo-bar {
color: red;
}
.foo:before {
content: "";
}
ですがネストには1つデメリットがあります。それは検索しにくい(またはできない)ことです。
デザイナーから「.foo-bar
を赤から青に変更してね」と言われました。Sassファイルで.foo-bar
を検索します。けれど検索には出てきません、.foo-bar
とはSassファイルで指定していないからです。
.foo {
&-bar {
color: red;
}
}
また、ネストが深くなると、今どのセレクタを参照しているのかが分かりにくくなります。
.foo {
&-bar {
...
...
...
...
...
...
}
&-baz {
...
...
...
...
...
...
}
}
早く書けることや、中にローカル変数を定義できることなど、ネストのメリットはありますが、変更するときに効率が落ちてしまわないかを考えてネストを使いましょう。
個人的には検索に影響が出にくい、疑似要素や疑似クラス、.is-active
のようなステートクラス、メディアクエリに使用を制限しています。
レスポンシブWebデザインではメディアクエリを使用して、ブレイクポイントを指定することがよくあります。そこでブレイクポイントを変数化して使用する方法があります。
$md: "screen and (min-width: 768px)";
// ブレイクポイントの変数をインターポレーション(`#{}`)でコンパイルできるようにする
@media #{$md} {
.foo {
width: 50%;
}
}
定義している値は変わりませんが、Mapというデータ型を使用するほうが柔軟に利用することができます。
$breakpoints: (
'sm': 'screen and (min-width: 400px)',
'md': 'screen and (min-width: 768px)',
'lg': 'screen and (min-width: 1000px)',
'xl': 'screen and (min-width: 1200px)',
) !default;
先ほど定義したMap型の変数を@mixinで呼び出してメディアクエリを使用します。
map-get()
でMap型の値('screen and (min-width: 400px)'
の部分)を取得しています。
$breakpoints: (
'sm': 'screen and (min-width: 400px)',
'md': 'screen and (min-width: 768px)',
'lg': 'screen and (min-width: 1000px)',
'xl': 'screen and (min-width: 1200px)',
) !default;
@mixin mq($breakpoint) {
@if map-has-key($breakpoints, $breakpoint) {
@media #{inspect(map-get($breakpoints, $breakpoint))} {
@content;
}
} @else {
@warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "
+ "Please make sure it is defined in `$breakpoints` map.";
}
}
@includeで@mixinを使用すると、.foo
はこのように出力されます。
// Sass
.foo {
@include mq(md) {
width: 50%;
}
}
/* CSS */
@media screen and (min-width: 768px) {
.foo {
width: 50%;
}
}
Map型の変数を使用すると、これ以外にもレスポンシブに対応したクラスを生成できます。
レスポンシブに対応した表示を切り替えるクラスが欲しい。
@mixin responsive($class, $bp: $breakpoints) {
#{$class} {
@content;
}
@each $suffix, $value in $bp {
@media #{$value} {
#{$class}-#{$suffix} {
@content;
}
}
}
}
// Sass
@include responsive(".u-dn") {
display: none !important;
}
/* CSS */
.u-dn {
display: none !important;
}
@media screen and (min-width: 400px) {
.u-dn-sm {
display: none !important;
}
}
@media screen and (min-width: 768px) {
.u-dn-md {
display: none !important;
}
}
@media screen and (min-width: 1000px) {
.u-dn-lg {
display: none !important;
}
}
@media screen and (min-width: 1200px) {
.u-dn-xl {
display: none !important;
}
}
グリッドレイアウトで12カラムの横幅をパーセンテージで指定できるクラスが欲しい。
$width-cols: 12 !default;
@mixin width($cols, $breakpoint: null) {
@each $col in $cols {
@for $i from 1 through $col {
.u-#{$i}of#{$col}#{$breakpoint} {
width: percentage($i / $col) !important;
}
}
}
}
@include width($width-cols);
// @requires - $breakpoints
@each $name, $breakpoint in $breakpoints {
@media #{$breakpoint} {
@include width($width-cols, -#{$name})
}
}
/* CSS */
.u-1of12 {
width: 8.33333% !important;
}
.u-2of12 {
width: 16.66667% !important;
}
.u-3of12 {
width: 25% !important;
}
/**
* `.u-12of12`まで続く、以降もブレイクポイントを追加して繰り返される
*/
@media screen and (min-width: 400px) {
.u-1of12-sm {
width: 8.33333% !important;
}
.u-2of12-sm {
width: 16.66667% !important;
}
.u-3of12-sm {
width: 25% !important;
}
}
- 変数で変更をしやすく
- パーシャルと@importでモジュールごとにファイルを管理する
- よく使うスタイルはデフォルトで置いておく
- CSSの構成案を導入する
- ネストは最小限に、検索しやすく
- ブレイクポイントはMapと@mixinで管理する
- レスポンシブに対応したクラスをつくる@mixin
SassはCSSを楽に早く書くために使用せず、CSSを管理しやすくするために使用しましょう。紙とペンでメモをとるときに、あとで読み返せなかったら意味がないですよね?