NAVER UITのSass Mixins職人(他称)の上村です。
今日はLess & Sass Advent calendar 2011の21日目です。
3日目に書かれている通り、NAVERでは半年ほど前から実務でSassを使っています。
今回は弊社で使用しているSassのディレクトリ/ファイル構成やMixinsについて解説します。
基本ディレクトリ/ファイル構成
今のところcss/sassディレクトリは下記のような構成を基本としています。
project
|~css/
| |-category-A_TRUNK.css
| `-category-B_TRUNK.css
|~sass/
|~core/
| |-_setting.scss
| |-_style-mixin-base.scss
| |-_style-mixin-layout.scss
| |-_style-mixin-module.scss
| |-_style-mixin-reset.scss
| |-_utility-css3.scss
| `-_utility.scss
|-_core.scss
|-_style-output-module.scss
|-category-A_TRUNK.scss
`-category-B_TRUNK.scss
- 先頭にアンダースコア( _ )がついているファイルは、partials (パーシャル)と呼ばれるインポート専用のファイルです。CSSファイルには変換されません。
- 弊社ではCSSファイルに変換するSCSSファイルは、ファイル名の末尾に「_TRUNK」とつけています。配信システムの都合上のものですが、パーシャルファイルとの区別がつきやすくなるので個人的には便利だと思っています。
それでは各ディレクトリ/ファイルについて説明をしていきます。
Coreディレクトリ
このディレクトリ内のファイル(以下、「コアファイル」と呼びます)に、サイトで共有する全ての変数と関数、Mixinsを記述します。
1枚のファイルに全てを記述するとかなり長いファイルになり、管理しづらくなるので、 設定用、ユーティリティ用、スタイルのMixins用の3種類に分けています。
1: 設定用SCSSファイル
_setting.scss は、他のコアファイルの基礎となるファイルで、サポートするブラウザや使用するベンダープリフィックス、全体で共有する画像のパスやDataURIの値などを設定します。
// # Support
$support-ie6: false;
$support-ie7: false;
$support-ie8: true;
$support-ie9: true;
$support-mozilla: true;
$support-webkit : true; // Chrome, Safari
$support-opera : true;
// # Vendor-prefixed CSS Property
$use-prefix-webkit: true;
$use-prefix-moz : true;
$use-prefix-ms : true;
$use-prefix-o : true;
// # IE
$use-ie-filter : false;
$use-ie-expression: false;
// # Path
$path-pj : "*****";
$path-img: "#{$path-pj}/img";
$path-sprite: "#{$path-img}/sprite.png";
// # DataURI
$dataURI-btn: "data:image/png;base64,*****";
案件によってはHTML5ではない事もあると思いますので、下記のように変数を設けて条件分岐に利用してもよいと思います。
// DOCTYPEがHTML5の場合のみ、
// $use-html5をtrueにし、スタイルを出力する。
$use-html5: true;
@if $use-html5 {
article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section {
display: block;
}
}
2: ユーティリティ用SCSSファイル
_utility.scss
画像置換やclearfixなどのスタイルセット用と、inline-block
やfont-family
といったプロパティ用のMixinsを記述しています。
スタイルセット用のMixinsの例
よくあるclearfixのMixinです。
@mixin clearfix {
@if $support-ie6 or $support-ie7 {
*zoom: 1;
}
&:after {
content: "";
display: block;
clear: both;
}
}
プロパティ用のMixinsの例
font-family
指定用のMixinです。
@mixin font-family($type, $important: false) {
@if $important == 'important' or $important == true {
$important: ' !important';
} @else {
$important: '';
}
@if $type == sans-serif {
font-family: sans-serif#{$important};
@if $support-ie6 {
_font-family: 'MS PGothic', sans-serif#{$important};
}
} @else if $type == serif {
font-family: serif#{$important};
@if $support-ie6 {
_font-family: 'MS Gothic', serif#{$important};
}
} @else if $type == meiryo {
font-family: Meiryo, 'MS PGothic', sans-serif#{$important};
} @else if $type == monospace {
font-family: monospace#{$important};
@if $support-ie6 {
_font-family: 'MS Gothic', monospace#{$important};
}
} @else if $type == hiragino {
font-family: 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif#{$important};
} @else if $type == verdana {
font-family: Verdana, Arial, Helvetica, sans-serif#{$important};
} @else if $type == tahoma {
font-family: Tahoma, Arial, Helvetica, sans-serif#{$important};
}
}
このMixinを使うときは、下記のようにします。
selectorA {
@include font-family("hiragino");
}
selectorB {
@include font-family("verdana", "important");
}
下記のように出力されます。
selectorA {
font-family: 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif;
}
selectorB {
font-family: Verdana, Arial, Helvetica, sans-serif !important;
}
_utility-css3.scss
ベンダープリフィックスが必要なプロパティのMixinsを記述しています。
なのでCSS3のプロパティだけではありませんが便宜上このファイル名にしています。
下記はborder-radius
のMixinです。
@mixin border-radius($property-value, $property-type: shorthand) {
// [NOTE]
// Firefox3.6以下のtopleftやbottomrightなどの
// 1コーナーのみを指定する記述には対応していません。
//
$property: border-radius;
@if $property-type != shorthand {
$property: border-#{$property-type}-radius;
// e.g. 'top-left', 'bottom-right'
}
// OUTPUT
@if $use-prefix-webkit { -webkit-#{$property}: #{$property-value}; }
@if $use-prefix-moz { -moz-#{$property}: #{$property-value}; }
#{$property}: #{$property-value};
}
このMixinを使うときは、下記のようにします。
.selectorA {
// 四つ角を指定。
@include border-radius("5px 10px 20px 5px");
}
.selectorB {
// 左上を5pxの角丸に指定。
@include border-radius("5px", "top-left");
}
$use-prefix-webkitと$use-prefix-mozがそれぞれ true
の場合は下記のように出力されます。
.selectorA {
-webkit-border-radius: 5px 10px 20px 5px;
-moz-border-radius: 5px 10px 20px 5px;
border-radius: 5px 10px 20px 5px;
}
.selectorB {
-webkit-border-top-left-radius: 5px;
-moz-border-top-left-radius: 5px;
border-top-left-radius: 5px;
}
このファイル内の他のMixinも基本的には次のルールに沿ってつくっています。
- Mixin名はCSSのプロパティ名をそのままか近いものにする。
- Mixinの引数はCSSのプロパティの値に使用できるものをそのまま渡せるようにする。
- 必要なベンダープリフィックスだけを記述する。
上記ルールのメリットとしては、下記が挙げられます。
- エディタによってはインクルード時のMixin名に補完機能が使える(かもしれない)。
- プロパティの値にはCSS3ジェネレーターサービスやツールで出力した値をそのままペーストして使用することができる。
- 必要なベンダープリフィックス付きプロパティのみを出力するのでファイルサイズを少なくすることができる。
また、CSSのプロパティとその値の指定方法・条件を覚えれば、Sassでもほぼそのまま使用することができますし、ベンダープリフィックスが不要になった場合にも覚えた事をそのまま活かすことができます。長期的にみて学習コストを下げることができるのではないかと思っています。
補足:ブラウザの実装差異のため上記ルールに沿うことができないプロパティもありますので、その場合は別の方法でMixinsをつくる必要があります。
3: 様々なスタイルのMixins用SCSSファイル
ファイル名から大体想像がつくと思いますが下記のような役割になっています。
_style-mixin-reset.scss | リセットスタイルの変数とMixinsを記述します。 |
---|---|
_style-mixin-base.scss | 基本スタイルの変数とMixinsを記述します。 |
_style-mixin-layout.scss | レイアウト用スタイルの変数とMixinsを記述します。 |
_style-mixin-module.scss | モジュール用スタイルの変数とMixinsを記述します。 |
ファイルの実際の内容は次のような感じです(Mixinsの名前は一般的なものに変えています)。
_style-mixin-reset.scss
@mixin reset-common {
// ここにリセットのスタイルを記述します。
:
html {
overflow-y: scroll;
}
:
@if $use-html5 {
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
}
:
}
_style-mixin-base.scss
@mixin base-common {
// ここにベースのスタイルを記述します。
:
body {
:
}
:
}
_style-mixin-layout.scss
@mixin layout-site-header {
// ここにレイアウトのスタイルを記述します。
:
.siteHeader {
:
}
.siteName {
:
}
.mainNav {
:
> ul {
:
}
}
:
}
@mixin layout-site-footer {
:
}
:
_style-mixin-module.scss
@mixin mod-pageTtl {
// ここにモジュールのスタイルを記述します。
.pageTtl {
:
}
}
:
// 記述するのは変数とMixins、関数などCSSに出力されないものだけです。
// 下記のように規則集合やCSSコメントは記述してはいけません。
/* @:topicPath */
.mod-topicPath {
:
}
全コアファイルのインポート用SCSSファイル
_core.scss でcoreディレクトリ内のファイルを全てインポートします。
@import "core/setting";
@import "core/utility";
@import "core/utility-css3";
@import "core/style-mixin-reset";
@import "core/style-mixin-base";
@import "core/style-mixin-layout";
@import "core/style-mixin-module";
1行で書くこともできますが読みづらいのでしていません。
@import "core/setting", "core/utility", ..., "core/style-mixin-module";
こうしておけば、
@import "core";
とするだけで、全てのコアファイルをインポートすることができます。
TRUNKファイル
TRUNKファイルに記述する内容は主に3つあります。
- _core.scss のインポート
- コアファイル内のMixinsのインクルード
- カテゴリ固有のスタイル
1: _core.scssのインポート
全コアファイルをインポートするために、前述の1行を追加します。
//--------------------------------------------------
// @:Import Core
//--------------------------------------------------
@import "core";
2:コアファイル内のMixinsのインクルード
リセットやベース、レイアウト用のMixins
まず、リセットやベース、レイアウト用のMixinsを下記のようにしてインクルードします(Mixinsの名前は一般的なものに変えています)。
//--------------------------------------------------
// @:Reset, Base
//--------------------------------------------------
@include reset-common;
@include base-common;
//--------------------------------------------------
// @:Layout
//--------------------------------------------------
@include layout-main-structure;
@include layout-site-header;
@include layout-site-footer;
案件によっては、html5doctorやnormalize.cssのリセットスタイルをMixinsにして利用すると便利だと思います。
必要な共有モジュールのMixins
次に、必要な共有モジュールのMixinsを下記のようにしてインクルードします。
//--------------------------------------------------
// @:Module
//--------------------------------------------------
@include mod-topicPath;
@include mod-pageTtl;
:
3: カテゴリ固有のスタイル
他カテゴリと共有しないスタイルを記述します。
//--------------------------------------------------
// @:Specific Style
//--------------------------------------------------
@mixin example {
:
}
selector {
$var: value;
//
@include example;
property: $var;
property: value;
}
Mixinsでスタイルの一元管理と共有を可能にする
Sassを使わないCSSのみの場合、module.cssといった名称のモジュール用のCSSファイルに使用頻度の高いスタイルを記述して、ほぼ全てのページで読み込ませていたと思います。
この場合、そのページ/カテゴリに必要のないスタイルも読み込むことがあると思います。
Sassを使う場合、共有するスタイルをcoreファイルにMixinsにして記述し、それを必要に応じてインクルードすることで、スタイルの一元管理と共有、そして不要なスタイルを出力しないといった事が可能になります。
全ページで必ず使う共有スタイルが多い場合、各TRUNKファイルにそれぞれ追加するのは手間がかかります。共有するモジュール用のパーシャルファイルを用意し、各TRUNKファイルに読み込ませておくのも手だと思います。
上記の場合、弊社では各TRUNKファイルに下記を追加し、_style-output-module.scssを読み込ませるようにしています。
@import "style-output-module";
おわりに
長くなりましたが、弊社で現在使用しているSassについての解説は以上になります。
まだまだ改善が必要だと思っていますが、本記事がSassを導入しようか迷っている方やすでに導入した方のお役に立てば幸いです。
最後までお読みいただきありがとうございます。