【Sass】@importを
@useに置き換えてみる
《FLOCSS対応》

Sassの@import記法が廃止予定

Sassの@import記法が2021年10月1日までに非推奨になり、翌年2022年10月1日までに廃止される予定です。その後は@use@forwardという新しいルールの記法で対応することになるのですが、そのまま置き換えても動かないので、各所調整や変更が必要になります。

筆者はここ5年くらいの制作全般でCSS設計に「FLOCSS」を使っています。FLOCSSは@importに依存しまくった設計でして、Gulpなどのビルド環境含め修正するのがかなり面倒くさくて、去年この変更の話を知ってから「やらなきゃな〜」と思いつつ見て見ぬふりをしていたら1年以上経ってしまいました。笑

そろそろ覚悟を決めて修正しようと思います。

SassをLibSassからDart Sassに変える

これまでnpmでnode-sassというパッケージが主流でしたが、これが「LibSass」と言われるものを使っていて、2020年10月に非推奨となりました。代わりに今後は「Dart Sass」を使っていくことになるのですが、今までnode-sassを使っていた場合は、新しくsassというDart Sass用のパッケージに変更する必要があります。

# node-sassをアンインストール
$ yarn remove node-sass

# sass(Dart Sass)とfibersをインストール
$ yarn add -D sass fibers

fibersはDart Sassの処理速度を上げるために必要なパッケージとのこと。詳しくはDart SassのGithubに書いてありますが、正直細かいことはよくわかりませんでした。内部的に使っている関数のパフォーマンスを補うために使うみたいなことが書いてます。別になくても動くようにしてるけど、あった方が早く処理できるから使ってねってことだと思います。公式がそう言ってるので使っておきましょう。

Gulpファイルを書き換える

未だにSassのコンパイルにGulp使ってるおじさんなので、Gulpファイルを修正します。
Webpack派の人は他の記事をお探しください。GulpでもWebpack使えるけど今回は割愛します。

Gulp4 + Babelで書きます。

import gulp from 'gulp';
import sass from 'gulp-sass';
import dartsass from 'sass';
sass.compiler = dartsass;
import fiber from 'fibers';
import browserSync from 'browser-sync';

function buildCss() {
  return gulp
    .src('./sass/**/*.scss', {
      allowEmpty: true,
      sourcemaps: true,
    })
    .pipe(
      sass({
        fiber: fiber,
        outputStyle: 'expanded',
      })
    )
    .pipe(
      gulp.dest('./css', {
        sourcemaps: '.',
      })
    )
    .pipe(
      browserSync.reload({
        stream: true,
      })
    );
}

function browsersync(done) {
  browserSync.init({
    proxy: 'localhost/test',
    open: 'external',
  });
  done();
}

function watcher(done) {
  gulp.watch('./**/*.scss', buildCss);
  done();
}

exports.default = gulp.series(watcher, browsersync);

従来の記述との変更ポイントは2つあります

まず1つ目。

import sass from 'gulp-sass'
import dartsass from 'sass'
sass.compiler = dartsass;

gulp-sassのコンパイラにDart Sassを使うように設定します。sass.compilerに新しくインストールしたDart Sassのパッケージを代入します。これでGulpでもDart Sassでコンパイルできるようになります。

そして2つ目。

import fiber from 'fibers'
.pipe(
      sass({
        fiber: fiber,
        outputStyle: 'expanded',
      })
)

fibersをインポートしてコンパイルのオプションに指定します。前述しましたが処理高速化のためになります。

これでDart Sassが使えるようになりました。

@importを@use・@forwardに置き換える方法

続いてscssファイル側で廃止予定の@import記法を新しい記法に書き換えます。

ただ、残念ながら@importをそのまま別の何かに書き換えても動くようになりません。@use@forwardというまた違うルールで置き換えていきます。

これまでは下記に例示する通り、_variable.scssのようなパーシャルを別ファイルから読み込んでいれば、それ以降で変数や関数、mixinをファイルをまたいでどこからでも呼び出して使えていました。

_variable.scss

$width : 900px;

style.scss

@import 'variable';
@import 'component/bar'; //変数を読み込んだ後に別ファイルをインポートすると

.foo {
  width : $width;
}

component/_bar.scss

.c-bar {
  width : $width; //ファイルをまたいでも先に読み込んだファイルの変数が使える
}

つまり読み込む順番さえ調整すれば、@importを入れ子にしまくっても先に読み込んだファイルの変数がそのまま使えます。これが@importの特性でしたが、@use@forwardではそのような特性はなくなります。

@use

@useを使う場合、名前空間を使って変数や関数をどのファイルのものか明示する必要があります。

@import 'variable';

.foo {
  width : $width;
}

従来は@importを使って↑のように書いていましたが、これが@useになると、

@use 'variable' as v;

.foo {
  width : v.$width;
}

↑こういう書き方に変わります。
@useで呼び出したファイルにasを使って名前空間を付け、変数名にその名前空間vを付けて使います。

@use 'variable';

.foo {
  width : $width;
}

↑のように変数名をそのまま書くと、$widthがUndefined variableとなりエラーになります。

これがどういうことかと言うと、変数がグローバルではなくファイルスコープになったということです。今まで@importで読み込んでいた場合は、先に読み込んでさえいれば後から読み込んだファイルの変数にはどこからでもアクセスできました。しかし@useでは、ファイルの先頭で明示的に変数の入ったファイルを読み込み、その変数には名前空間を使ってしかアクセスできなくなります。「ここで使っている変数はこのファイルの変数だよ」って感じで、変数がどこから来たのか明確にしていくって感じですね。ちなみに変数だけでなく、mixinや関数も同じです。

@use 'variable' as v;
@use 'mixin' as m;

.foo {
  width : v.$width-sp;

  @include m.min-screen(v.$size-pc) {
    width : v.$width-pc;
    
  }
}

ファイルを読み込む時にasで名前空間を付けて、変数や関数を使う時には名前空間.変数名や関数名のように使います。

まぁ確かにこのルールになると、複数で開発する時とか他の人が書いたコードを修正するときなんかはわかりやすいのかも。突然出て来た独自のmixinや変数って、自分ルールでCSSを設計してた場合に、どこに書いてるか、上書きされてないか、とかをいちいちファイルを探して調べる必要があるケースが想像できます。名前空間があれば変数やmixinを上書きするリスクはなくなるし、ファイル分けて使いたいなら各ファイルの先頭に@useで元の場所を明示的にしておけばわかりやすくていいよねってことなのかなーと思います。

@forward

@forwardはファイルをまたいで値を受け渡すことができます。

これまでFLOCSSなどのCSS設計で運用してきた場合、@importを入れ子にしたい場合があります。
それを下記のように@useを使おうとすると動きません。

_variable.scss

$red : #f00;
$yellow : #ff0;

foundation/_index.scss

@use 'variable'
@use 'mixin'
@use 'function'

style.scss

@use "foundation" as v;

.foo {
  //変数が読み込めずエラーになる
  background-color : v.$red;
}

意図としては関数や変数のパーシャルを1ファイルにまとめてインポートして使いたいのですが、@useではそれができません。こういった場合に@forwardを使います。

foundation/_index.scss

@forward 'variable'
@forward 'mixin'
@forward 'function'

style.css

@use "foundation" as global;

.foo {
  background-color : global.$red;
  //mixinやfunctionも@forwardを使っているとglobalという名前空間でまとめて呼び出せる
  @include global.min-screen(801px) {
    background-color : global.$yellow;
  }
}

ただし、@useと違ってファイル間でスコープを受け渡しするだけの役割なので、@forwardを使ったファイル内で変数として使うことはできません。

foundation/_index.scss

@forward 'variable' as v
@forward 'mixin'
@forward 'function'

.bar {
  // これはエラーになる
  color : v.$red;
}

この場合は@useと併記する必要があるみたいです。

@forward 'variable'
@forward 'mixin'
@forward 'function'

@use 'variable' as v;

.bar {
  color : v.$red;
}

@use@forwardは役割が全く違うので同時に使っても問題ないようです。

ちなみに@forwardで名前空間を定義した場合は、受け渡した先で使えるプレフィックス(接頭辞)となります。

foundation/_index.scss

@forward 'variable' as v-*;
@forward 'mixin' as v-*;

style.scss

@use 'foundation' as global;

.foo {
  background-color : global.$v-red;
  @include global.m-min-screen(801px) {
    background-color : global.$v-yellow;
  }
}

これ公式に書いてなくて若干ハマりました。@forwardで付けたプレフィックスはmixinや関数のときはそのまま先頭に着くのですが、変数の場合は$の後ろに付きます。

background-color : global.$v-red; //○
background-color : global.v-$red; //× エラーになる

公式見てもmixinの例しかないので、そのまま先頭に付けてあれ?ってなりました。
@forwardのプレフィックスはあまり使う機会なさそうなのでいいんですけどね。

FLOCSSを@useに合わせて調整する

@importを使いまくって、どこからでも変数使い放題のCSS設計のFLOCSSですが、すべてのパーシャルファイルに@useで変数やmixinを読み込む必要があります。

そのため、変数などのファイルは新たにglobalというフォルダを作り、そこから一括で読み込めるようにします。

FLOCSSのディレクトリ構成

├── /sass/ 
   ├── /global/ ← このフォルダを作る
     ├── /foundation/
     ├── /layout/
     ├── /object/
        ├── /component/
        ├── /project/
        ├── /scope/
        └── /utility/
   └── style.scss

これまでfoundationフォルダに入れてあった_variable.scss_function.scss_mixin.scssなどの共通ファイルをglobalフォルダに移動させ、global/_index.scssから一括で読み込めるように下記のファイルを作ります。

global/_index.scss

@forward "variable";
@forward "mixin";
@forward "function";

あとは各ファイルの先頭に下記のように読み込みます。(相対パスの位置は適宜変えてください。)

@use '../global' as g;

そしてcomponentやprojectの各ファイル内で変数やmixinに名前空間を振っていけばOKです。

component/_foo.scss

@use '../global' as g;

.c-foo {
  background-color : g.$red;
  @include g.min-screen(801px) {
    background-color : g.$yellow;
  }
}

ひとまずこれで@importは置き換えられました。

あとはstyle.scss@import@useに変更すれば、FLOCSSの変更対応はひとまず完了です。

@use "foundation";
@use "layout";
@use "object/component";
@use "object/project";
@use "object/utility";

↑各フォルダに_index.scssというパーシャルを作って読み込むことを想定しています。

ビルトインモジュールについて

@importの話とは別になりますが、Dart Sassでのその他の変更についても触れておきます。

lightendarkenといったSass関数や、60px / 3のような除算処理などが、LibSassの時はコンパイル時に自動で組み込まれていたのですんなり使えていましたが、Dart Sassからは「ビルトインモジュール」となり扱い方が変わる様です。

Sass: Built-In Modules

https://sass-lang.com/documentation/modules

明示的に使いたいモジュールを読み込んで、新しい記法に変えないといけなくなります。そのままlightenなどと書いても使えなくなる模様です。

この記事の執筆時点(2021.6.2)では、前述したGulpのコードを使った場合はまだlightendarkenrgbaは問題なくコンパイルされていました。おそらく段階的に使えなくなっていくのでしょう。

Sass関数の書き換え

今後、Sass関数は下記のようにモジュールを読み込んで別の書き方に変更されます。

@use "sass:color";

.foo {
  //lighten
  color.scale(#fad, $lightness: 30%);
}

.bar {
  //darken
  color: color.scale(#fad, $lightness: -30%);
}

.baz {
  //rgba
  color: color.scale(#fad, $alpha: -40%);
}

↓コンパイル結果

.foo {
  //lighten
  color: #ffc4e7;
}

.bar {
  //darken
  color: #ff2baa;
}

.baz {
  //rgba
  color: rgba(255, 170, 221, 0.6);
}

sass:colorについては他にも関数があるので、詳しくは公式ドキュメントで確認してみてください。

sass:color

https://sass-lang.com/documentation/modules/color

除算処理の書き換え

60px / 3のような除算(割り算)処理はすでにDart Sassでは使えなくなっています。

.foo {
  padding : (60px / 3); //× エラーになる
}

下記のように書き換えます。↓

@use "sass:math";

.foo {
  padding: math.div(60px, 3);
}

関数やmixinをたくさん使っている人は、この修正がかなり大変だろうなと思います。
最近はcssでcalc()が使えるのでそっちに書き換えた方が楽かもしれませんね。

さいごに

FLOCSSで使われている@import@useに置き換える方法について、下記内容をメモしました。

  • LibSassからDart Sassへの変更方法
  • Gulpファイルの変更方法
  • scssファイルの@importを@use・@forwardに置き換える方法
  • @useに合わせたCSS設計「FLOCSS」の調整方法
  • ビルトインモジュールでSass関数などを書き換える方法

@importは使えなくなるのがわかっているので、変更方法は早めに押さえておきましょう!

個人的な感想としては、正直@useへの変更は「めっちゃめんどい」です!笑

最終的に文句が出ちゃいましたけど、今回のようなSassの致命的な変更に限らず、TypeScriptにしろVueにしろ、GulpにしろWebpackにしろ、Nodeにしろnpmにしろ、古くなったルールを新しいルールに置き換えるっていう作業はよくあることなので、こういった機会に改めて内容を整理してみると新しい発見があったりして勉強になります。

久々にGulpファイル書いたら、開発に使ってるGulpファイルも整理したくなって来たのでまたそれについても更新しようかな。いい感じにできたら過去記事リライトします!

参考サイト

Dart Sass(@use)の基本的な書き方と@importから乗り換える方法

Sassで除算するときはsass:mathモジュールのdiv関数を使おう

追記(2021.11.24)

その後、この記事の設定で使いにくかった部分について修正してみました。

記事一覧

RELATED

inoue
TRY

【WordPress】GA4連携の人気記事ランキング機能を自作プラグイン化してみた

inoue
TRY

【netlify】ビルドイメージを更新 [ Ubuntu Xenial 16.04 → Ubuntu Focal 20.04 ]

inoue
TRY

スクリーンショットのAPI「screendot」を使ってみた

inoue
TRY

DartSassがなかなか辛かったのでGulpを修正してみた

inoue
TRY

【howler.js】ストリーミング音源からオーディオビジュアライザーを作る

inoue
TRY

Simple GA Ranking[ver2.1.6]が表示されないので調べてみた

NEW POSTS

inoue
TIPS

【CSS + JS】テキストの無限ループアニメーション

inoue
TIPS

【Shopify】カートへの遷移を飛ばしてチェックアウトに進むボタンを設置する

inoue
TIPS

【JS】PhotoSwipe v5を使って画像をポップアップ表示する

inoue
TIPS

gulpでjpg・pngからAVIF画像を生成する

inoue
TIPS

【JS】MutationObserverでDOMを監視[PhotoSwipe(v5)+Swiper(v8)連携]

inoue
TIPS

【Google Sheets API】 スプレッドシートのデータをJSONで取得する

ブログ記事一覧
  • HOME
  • TRY
  • 【Sass】@importを@useに置き換えてみる《FLOCSS対応》