Sass(SCSS)の自分が使いそうで便利そうなものをつまみ食い
CSS変数(カスタムプロパティ)が普通に使用できるようになってからSassに感じていた魅力は半分以下に低下した気がするけれど、そもそもどんなことができるのかを網羅的に調べたことはなかったので目を通してみる。
完全なレスポンシブに対応するには避けて通れないかもしれない感がでてきているのは確かだ。
ファイルの圧縮
最終的にCSSファイルは圧縮した方がメリットが大きいと思うのでそうしたいのですが、公開の直前まで弄っているのがCSSファイルだったりもします。
…で、公開して問題なかったと確認できた頃には力尽きていてCSSファイルの圧縮なんて面倒なことこの上ないです。
CSSのコンプレサーと言うか、SCSSのコンパイラにはVSCodeの拡張のLive Sass Compilerを使用しているので、保存のたびに圧縮してしまえばいい。
"liveSassCompile.settings.formats":[
{
"format": "expanded",
"extensionName": ".normal.css",
"savePath": null
},
{
"format": "compressed",
"extensionName": ".css",
"savePath": null
},
]
ちょっと必要なこともあって未圧縮のCSSも同時に書き出すようにしている。
保存のたびにコンパイルするといちいちVSCodeのコンソールが出てきてウザかったけど、拡張の設定からエラー時のみに変えられたのでよかった。
一行コメント
// これはコンパイル圧縮すると消えるコメント
/* これは圧縮すると消えるコメント */
/*! 圧縮しても消えないコメント(って必要なのか?) */
うん。便利。// って打ちやすいのと複数行コメントと見栄えを分けられて嬉しい。
ネスト
便利そうだけでれど、普通のsectionレベルだとあまり恩恵を感じない。モジュール作成時に活躍するイメージかなぁ。
.attentionBox {
padding: 20px 40px;
p:last-of-type,ul:last-of-type {
margin-bottom: 0;
}
}
あとは @mixin と @include を併せて使うといい感じかも?
プロパティもネストできる
.attentionBox {
border: {
top: 1px solid #ccc;
}
}
これは何に使うと便利なんだろう?可読性の担保なのかな?
メディアクエリのネスト
.attentionBox {
padding-inline: 5%;
@media screen and (width > 640px){
padding-inline: 40px
}
}
これは神。便利というか完全に可読性。
いつもメディアクエリ(コンテナクエリ)を書く際に
- セレクタの直後に書く
- ひと固まりのセクションが終わった後に書く
- CSS全体の最後に書く
- 別ファイルに書く
で悩ましいことがあったけれど、モジュールで考えるならこれで統一もあり。
ただ、全体レイアウト部分は二番目くらいの単位の方が読みやすいかも。
親セレクタの参照
a {
font-weight: bold;
color: #ff0;
&:hover {
text-decoration: underline;
}
.attentionBox & {
color: #00f;
&:hover {
text-decoration: none;
}
}
}
便利かどうかよりも、知っていないとまとめて書くことができないこともある。Sassを使用するならまとめられる書き方ができる部分はなるべくまとめたい。
別Sassファイルの読み込み
ファイル名の先頭にアンダースコアを付けたscssファイルは部分的なファイルであるとみなされてコンパイルされないらしい。つまり各種変数の設定などを書いておいて、そのファイルを他のscssファイルで使用するというイメージ。
$main-text-color: #212121;
@use 'setting';
body {
color: setting.$main-text-color;
}
- @useで読み込むときに先頭の_や拡張子.scssは不要
- 変数を使用する際には名前空間が必要
- _setting.scss で @use を使用してさらに _setting2.scss を読み込むことは可能
- コンパイルされないと書いたが、_setting.scss に書いた「普通のCSS」は@useで呼び出された時に1回だけ出力される
名前空間の変更
settingとかなら許容範囲ですが、名前空間の文字列が長い場合は置き換えも可能。
@use 'setting' as st;
body {
color: st.$main-text-color;
}
以下のようにすると名前空間無しで参照も可能
@use 'setting' as *;
body {
color: $main-text-color;
}
一人での開発や他のSassファイルを要さない場合はこれでよさそう。競合を起こすほど複雑にはしないか、そもそも変数名で工夫するという方法もある。
変数名が長くなったら本末転倒か…?
:::Message
…たぶん、この辺りは多数派に合わせておいた方がよさげ。
:::
変数
$main-width: 960px;
.wrap {
width: $main-width;
}
説明不要かな。変数はどのタイミング(行)でも指定でき、指定した以後にのみ適用される。
ただし、セレクタのスコープの中で宣言したものはその範囲内でのみ使用可能。つまりネストもうまく利用できるし、グローバル(トップレベル?)の概念もある。
歴史的な背景から、アンダースコアとハイフンは同一のものとして扱われるらしい。ちょっとキモい。
変数名の先頭は数字はNG。連続したハイフン(やアンダースコアも?)から始まるのもダメ。記号もその二つ以外は使えない。
連続していないハイフンやアンダースコアから始まった変数は「プライベートメンバー」となり、外部のファイルからの参照ができない変数となる。
!default
変数の値が設定されていればそれを、設定されてなければこっちを使ってねという指定。
$main-width: 960px !default;
インターポレーション
#{ } で変数の結果を出力できる。セレクタ名でもプロパティ名でも数値でもなんでも可。
$img_path: "../assets/img/";
body {
background-image: url(#{$img_path}background.jpg);
}
だいたいこんな使い方が多そうかな?
cssの @import 的なものがある
@use 'foundation';
メインのscssファイルで上記のように指定すると _index.scss が自動で読みこまれるらしい。
@use 'base';
@use 'setting';
@use 'color';
などとしておけば @use 'foundation' を指定するだけでOK。
追加などがあれば _index.scss を書き換える。
・・・と思ったけど、これだと変数とか参照できなくて使えない。そんな時は @forward らしい。
@forward で流す
@use はそのファイル内で「使う」というイメージ。@forwardはそのファイルは踏み台で、次のファイルへ橋渡しするイメージ。
@forward 'base';
@forward 'setting';
@forward 'color';
_index.scss はただのハブでしかないのでこれでいい。
もし _index.scss で base とかに書いたものを「使いたい」場合は @use も併用する。
@forward 'base';
@forward 'setting';
@forward 'color';
@use 'base';
まぁ、あんまりこういうことはしなさそうな雰囲気。
scssをモジュール単位で使用していくと、関数名や変数名、mixinなどが被ってしまうことがある。いちいち長ったらしい名前や前置詞を考えてもいいけれど、@forward するときに自動で付与してくれる機能があるという。
@forward 'button' as btn-*;
うーん。プレフィクスで細かく管理するか、大雑把にネーミングで管理するか流派がわかれそう。
たぶんプレフィクスで細かく管理するのが上等(もしくは常套)な気がするけれど、ファーストインプレッションでは競合に注意した命名でざっくばらんにやるのが楽そう。。。
あと、@forward するときに、任意のものだけを参照させたり、もしくは参照させないようにすることもできるみたいだけど、あんまり使わなそう。
キーワードはshowとhide。
@mixin と @include
これが一番の目玉なのかな?ミックスイン。パッと見、某SNSの名称に見える。
簡単に言えばよく使うcssのセットを使いまわしできるようにするということ。
@mixin box_Type-1 {
border: 1px solid #ccc;
padding: 24px 32px;
background-color: #efefef;
}
上記のように定義して、以下のように使う。
.attentionArea {
@include box_Type-1;
}
.asideArea {
@include box_Type-1;
}
コードが面倒なので書かないけれど、ミックスイン同士のネストも可能。
どの単位までミックスインを作成するかは難しい。1行のものならそれ自体を書いた方が速いし、モジュールのどの部分を部品として切り出すかはセンスが問われそう。
別ファイルのミックスインを呼び出す方法は変数の呼出し方と変わらない。名前空間つけたりという感じ。スコープもあって、特定のclassの中で作成したものはそのclass内だけしか使えない。
ミックスインの引数
上記のように「灰色の囲い」というミックスインを作成したあと、他にも「黄色の囲い」や「赤色の囲い」なども必要となったときにどうするか?
それぞれのミックスインを作成してもいいが、色の部分だけ変数にしてしまう方法がある。
@mixin box_Type-1($color1,$color2) {
border: 1px solid $color1;
padding: 24px 32px;
background-color: $color2;
}
.attentionArea {
@include box_Type-1(#f00,#fff0f0);
}
というイメージ。
ただ、これだといちいち引数を渡さなければならない。基本的には灰色で、たまーーに黄色や赤色があるというような場合は引数のデフォルト値を設定すればいい。
@mixin box_Type-1($color1:#ccc,$color2:#efefef) {
border: 1px solid $color1;
padding: 24px 32px;
background-color: $color2;
}
.attentionArea {
@include box_Type-1;
}
呼び出すときに引数を持たせない場合は括弧も値も省略できる。これはミックスインを作る時も同じ。引数があろうがなかろうが()は付けておくのがわかりやすいかも?
引数の値が複数ある場合、
- どちらもデフォルト値
- どちらも変更値(もしくはデフォルト値と同じ値を指定)
にしないと駄目で、つまり
.attentionArea {
@include box_Type-1(,#fff0f0);
}
みたいなのは駄目。面倒でも
.attentionArea {
@include box_Type-1(#ccc,#fff0f0);
}
という指定が必要になる。
ただし、値だけではなく「引数名:値」の形式で渡せば1個だけでもいいし、順番も気にしなくていい。
.attentionArea {
@include box_Type-1($color2:#fff0f0);
}
つまりこれはOK。
複数の値をセットで引数にしたい場合
複数というのは「カンマで区切られる2セット以上の値」らしい。単純に 1px solid blue という記述であれば1個として引数に持たせられる。
CSSでカンマで区切る複数の値って・・・?
あぁ、box-shadowとか複数のbackground-imageとかですね。
あまり使わないかなぁ。使ったとしてもミックスインにするのはさらに可能性が低いかも?
一応、やり方としては、括弧で囲って配列にするといいみたい。
@mixin box_Type-2($shadow) {
box-shadow:($shadow);
}
.attentionArea {
@include box_Type-2([2px 2px 4px #c5c5c5,-2px -2px 4px #c5c5c5]);
}
@content というワンポイント
ミックスイン内で @content という記述を入れておくと、@includeで呼び出すときに波括弧内の記述がそこに展開されるという仕様がある。
@mixin box {
border: 1px solid $color1;
padding: 24px 32px;
background-color: $color2;
@content;
}
.alert {
@include box {
color: #f00;
font-weight: bold;
}
}
これだけ見ると、
.alert {
@include box;
color: #f00;
font-weight: bold;
}
これと何が違うのかわからなかったので、使い道を調べてみたところ、メディアクエリのミックスインを作っておくと便利だということがわかった。
@mixin tab {
@media (640px <= width < 920px) {
@content;
}
}
@mixin pc {
@media (920px <= width) {
@content;
}
}
.box {
padding-inline: 5%;
@include tab {
padding-inline: 8%;
}
@include pc {
padding-inline: 40px;
}
}
こういう書き方ができて非常にスッキリする。これはいい。
もともと想定されているブレークポイントの(Bootstrap的な)書き方があるみたいだけど、あまり好きじゃないのでこれがいい。
@contentでも引数を使えるみたいだけど、今のところ使い道がわからないので省略。
ifとか使うと便利なのかな?
@extend は無理して使わないことにする
@extend がミックスインと比較して優位な場合もあるみたいだけれど、メディアクエリ内では使えなかったりと扱い難さもあるため常用は見送り。
@if @each @for @while
これらもいつかは使う日がくるとは思うものの、おそらく最初の設計時に使用するだけで常用はしないだろう。数字つきのアイコン ic1.png~ic20.png までを指定する時とかは便利そうだけど、それくらいならコピペでいい気もする。
「使える」ということだけ知っておく。
ビルトインモジュール
色々と複雑で難しいことができるようだ。今のところ、
- なぜそれができるのか?
- どこでそれを使うのか?
- そんな機会はあるのか?
がわからないので踏み込まないようにする。
@functionで関数を自作できる
使うか使わないか微妙なところ。
@function double($val) {
@return $val * 2;
}
.box {
width: double(300px);
}
↓
.box {
width: 600px;
}
という感じ。
引数も使えるし、引数のデフォルト値の指定も可能。
@debug で値を出力
保存のたびにコンパイルしているから不要かなぁ。
@error や @warn も必要が出たらでよさそう。
Sassを使っていくにあたって
冒頭に書いた通りコンパイルにはLive Sass Compilerを使用。
あとはSCSSフォルダを作成して、公開用のCSS(圧縮)と確認用のCSS(非圧縮)を出力してデバッグも納品もしやすいようにすればいい。
project
├ assets
│ ├ css
│ │ ├ style.css
│ │ └ style.css.map
│ ├ css-nocomp
│ │ ├ style.css
│ │ └ style.css.map
│ └ scss
│ ├ style.scss
│ ├ _index.scss
│ ├ _hoge.scss
│ └ _fuga.scss
└ index.html
基本的な階層はこんな感じにしておいて、プロジェクトで変わる場合は新たなワークスペースで出力設定を変えてあげればよさそう。
結果的に設定は以下のようになった。
"liveSassCompile.settings.formats":[
{
"format": "expanded",
"extensionName": ".css",
"savePath": "~/../css-nocomp"
},
{
"format": "compressed",
"extensionName": ".css",
"savePath": "~/../css"
},
],
今まであまりVSCodeのワークスペースやエクスプローラーは使用してこなかったけれど、これを機に調べ直して使いやすいように整備した。
Workspace Explorer というVSCodeの拡張がいい仕事をしてくれている。
1.6.2まではエクスプローラーの下に出ていたのに、それより新しいものはアイコンをクリックしてエクスプローラーではない表示になってしまうので古いバージョンの方を使用している。
さて、これで本格的にSassを使用する下地が揃ったけれど、どれくらい有用に使えるかはわからない。まずは肩肘張らずに便利そうなところだけ使ってみたり、最終的にScssに逆コンパイル的なことをする時間をつくってみたりしてみよう。
あれ、やっぱりこんな感じがいいかも?
project
├ src
│ ├ scss
│ │ ├ style.scss
│ │ ├ _index.scss
│ │ ├ _hoge.scss
│ │ └ _fuga.scss
│ └ css-nocomp
│ ├ style.css
│ └ style.css.map
└ public_html
├ assets
│ ├ css
│ │ ├ style.css
│ │ └ style.css.map
│ ├ js
│ └ media
└ index.html
Discussion