SassからPostCSSにしようとして「いや、今じゃない」と移行をやめた話

※2024年現在はgulpからAstroに移行し、自分の制作環境に対する考え方も少し変わってきています。この記事は当時のものです。
長年gulpとSassでやってきましたが、最近思うところがあり、npm-scriptとPostCSSに変えようと最近頑張っていました。
…が、SassでできていたことがPostCSSでできなくなる部分が あり、またそれを許容するほどのメリットも今のところ感じられず、これは今乗り換えるべきじゃない、現状維持だという結論に至りました。
移行しようとした理由
dart-sassへの移行に苦労した
Sass疲れた…と感じた最近の出来事が、dart-sassへの移行です。
下記ブログの時です。
Dart Sassに移行(Gulp / Node 16 / glob対応)
当時、globbingをdart-sassで使う方法がググってもなく、npmパッケージをnpmサイトで直接検索してやっと対応しているパッケージを見つけましたが、「パッケージを探す」という直接的に技術として身につかない(しかも流行り廃れのある)作業に、なんだかなあという気持ちが生まれました。
無駄だったとは思いませんが、個人的にはこんなことよりももっと他に時間を使いたいことが山ほどあります。(パッケージがなければ作るかとも考えましたが、そんな力はありませんでした)
PostCSSにしても、パッケージ入れ替えなどの作業が発生する点は変わらないかもしれませんが、Sassにちょっと不満を抱いた出来事でした。
新しいCSS記述方法への対応に一抹の不安
さらに、今年に入ってからCSS周りに大きな変化というか、CSSでできることが増える印象です。
カスケーディングレイヤーやコンテナクエリなどです。
コンテナクエリは現時点(2022年4月)でまだブラウザでデフォルト実装されていませんが、
カスケードレイヤーはもうほぼ全てのブラウザで使用可能です。
ブラウザの実装状況
https://caniuse.com/css-container-queries
https://caniuse.com/css-cascade-layers
scssでカスケードレイヤーを使ってみると、@layerのところが認識されていません。

それでもスルーでコンパイルされ、一応CSSで使うことはできるのですが、なんだか気になる感じでした。
今後SassやCSSで何か大きな変更があるたびに、gulpのパッケージを探したり、方針を変更し続けなければいけないということを感じ始めました。
gulpからnpm-scriptへ移行を考えた時に、Sassのglobが利用できない
gulpは便利なのですが、npm-scriptにしたという例をよく見かけるようになり、dart-sassへの移行で運良くgulp用のパッケージがあったからよかったものの、結構探したなぁと思い出しました。
また、それとは別に、gulpを立ち上げても一度で立ち上がらないことが頻発するようになりました。これは自分のgulpfile.jsの書き方のせいかもしれませんが、いろいろ試行錯誤したり人を頼っても解決策が見つからず、3回くらいコマンドをうってたちあげなおすとやっと立ち上がる…(一度立ち上がったあとは特に問題ない)という状態で使っています。
追記:gulpが一度で立ち上がらない件について。詳しくはわからないのですが、マシンとの相性の問題でgulpfile.jsに追記することで解決しました。
さらに、現在はAstroを使っているのでgulpは使っていません(Sassは現役)。
若干のストレスを感じているので、これをきっかけにnpm-scriptで同じことができるように考えてみようと思いました。
しかし、この作業でまた行き詰まりました。
npm-scriptでdart-sassを使い、さらにglobを適用させる方法が見つからない。
またglobbingか……!!!ということで、調べていくうちにPostCSSならいけそうだという結論に辿り着き、Sassを諦めPostCSSで同じことができないかとまた調べていくことになりました。
PostCSSが、Web開発のフレームワークに使われているということも「使おう」と思った大きな理由です。よく使われているものは市民権を得るので強いです。やっておいて損はないと考えました。
PostCSSの構成
PostCssは、結果的に以下のような構成になりました。
module.exports = {
plugins: {
'postcss-easy-import': {extensions:'.pcss'},
'postcss-simple-vars': {},
'postcss-mixins': {},
'postcss-nested': {},
'cssnano': {
preset:['lite',{normalizeWhitespace:false}],
},
'autoprefixer': {
"grid": 'autoplace',
"cascade": false
},
'postcss-merge-queries':{},
}
}
postcss-easy-import
glob対応のimportのパッケージを探していましたが、どうも「postcss-import」と「postcss-import-ext-glob」の組み合わせではうまくいきませんでした。
定番っぽいのになぜだろう…と思っていたらこんなページがあったので、
https://www.npmtrends.com/postcss-easy-import-vs-postcss-import-ext-glob
この「postcss-easy-import」の方を試してみたら、あっさりいけました。
@import 'src/common/**/*.pcss';
これで、フォルダ内のもの全てインポートできるようになります。
postcss-simple-vars
Sassの変数の書き方ができるPostCSSプラグインです。
CSSカスタムプロパティも検討しましたが、メディアクエリの規則の中で使えない(@media(max-width:var(--widthTab)){}
のような書き方は不可)のと、Sassの記法に近い方が導入しやすいと思ったので取り入れました。
postcss-mixins
mixinはどうしても必要です。特にメディアクエリを簡単に書きたいので、同じような記法でかけるものを探しました。
@define-mixin sp {
@media (max-width: $widthTab) {
@mixin-content;
}
}
/* 使うところ */
@mixin sp{
display: none;
}
このmixinで、scssのmixinと比べて使い勝手が悪くなった点が3つあります。うち2つは、postcss-simple-varsとの組み合わせによるものです。
Sassでできていたが、postcss-mixinsに変えてできなくなったところ
1、計算できない
@media(max-width: ここ) に変数を入れることはできるのですが、scssでは@media (max-width: ($widthTab - 1)) {
のような形で、計算もできた…。このパッケージでは不可でした。
CSSのカスタムプロパティを使っても不可です。
計算部分を変数にしなければいけるのでまだ許容範囲です。
2、mixinのネストができない
例えばスマホ用にだけmixinのスタイルを設定したい場合に、下記のような形で書くことができません。
.sample{
@mixin sp{
@mixin section-center;
}
}
一応解決策としては、@define-mixin
の中にmixinを書くことはできるので、こんなのを作っておいて
@define-mixin section-center-sp{
@mixin sp{
margin-left:auto;
margin-right:auto;
max-width:90%;
width:90%;
}
}
使うときは、メディアクエリmixinの外に書く
.sample{
@mixin section-center-sp;
@mixin sp{
display: block;
}
}
これで目的は達成できます。でもできれば、スマホのスタイルはメディアクエリmixinの中に書きたいところです…。
3、mixinの中で変数が使えない
変数は、postcss-simple-varsで使えるようになります。Sassと同じで、ドルマークつけるだけのお手軽な使い心地がよいです。
…が、これをmixinの中で使うのは不可のようで、
例えば下記のように、スマホで$themeColorという変数を使うと
$themeColor:#ef4d63;
.sample{
@mixin sp{
color: $themeColor;
}
}
変換されずにそのまま出ています。
.sample{
color: $themeColor;
}
解決策としては、postcss-simple-varsの変数を使わずにCSSのカスタムプロパティを使う。
:root {
--themeColor: #ef4d63;
}
.sample{
@mixin sp{
color: var(--themeColor);
}
}
当然これならいけるのですが、このハイフン二つとvarを受け入れる心の準備はまだできていない…。慣れれば大したことじゃないかもしれませんが。
2023/2 追記:CSSカスタムプロパティに関してはそろそろ積極的に使っていいと思ってきた。
postcss-nested
プロパティをネストで書くことができます。これもScssで必須だったので、追加しました。
postcss-autoprefixer
最初は、ネットの記事を参考にして
'autoprefixer': {
"browserslist": "last 2 versions",
}
と書いてましたが、下記エラー。
Error: Loading PostCSS Plugin failed: Change browserslist option to overrideBrowserslist in Autoprefixer
overrideBrowserslistを使用してくださいといわれるが、
公式には
overrideBrowserslist (array): list of queries for target browsers. Try to not use it. The best practice is to use .browserslistrc config or browserslist key in package.json to share target browsers with Babel, ESLint and Stylelint. See Browserslist docs for available queries and default value.
overrideBrowserslist (array): 対象ブラウザに対するクエリのリスト。なるべく使用しないようにしましょう。Babel、ESLint、Stylelintでターゲットブラウザを共有するには、package.jsonの.browserslistrc configまたはbrowserslist keyを使用することがベストプラクティスです。
なるべく使用するなと書かれている?
なので、最終的にはgridとcascadeを入れておくことに。
'autoprefixer': {
"grid": 'autoplace',
"cascade": false
},
grid
これはgulpのautoprefixerでも有効にしていました。
グリッドを使用します。「autoplace" は、グリッドレイアウトの -ms- 接頭辞を有効にし、いくつかの限定的な自動配置をサポートします。
cascade
コンパイル後のCSSのインデントがちょっとかわります。


cssnano
cssファイルを最適化できるプラグインです。
改行を全部無くしたりいろんなことができるのですが、コメントを削除したかったのでいれました。
presetのdefaultだとコメント削除だけでなくいろいろ他にも最適化されて、改行が全部なくなってしまうので、liteを採用し、normalizeWhitespaceをオフにしてコメント削除だけを残すようにしました。
https://cssnano.co/docs/what-are-optimisations/
cssnano-preset-lite
をインストールし、下記でliteを適用します。
'cssnano': {
preset:['lite',{normalizeWhitespace:false}],
},
CSSの最適化は推奨されていますが、Webサイトデータの納品をする時に、CSSが圧縮されていると何かと不便なこともよくあります。
納品相手が初心者でも編集しやすい綺麗な形のCSSが作りたかったので、liteがちょうど良い選択肢でした。
postcss-merge-queries
吐き出されたCSSのメディアクエリをまとめてくれます。非推奨になったcss-mquery-packerの後継のようです。
他にもpostcss-combine-media-queryというパッケージもあるようですが、これを加えると、なぜかmediaの記述がが丸ごと消えました・・・のでやめました。何かと競合してるのかもしれないです。
採用見送りpostcss-extend
Sassでextendを使うことはほぼないので、今回も使わないことにしました。
上記で書いたように、mixinをネストにしてたところがうまくいかないので、代わりにextendを使ってみようと思っていろいろやってみましたが、下記のようにアンパサンドをつかった書き方がうまくいかなかった(変換されずそのままcssファイルに出た)ので、その記録だけしておこうと思います。
.sample{
&-inner{
@extend .section-center;
}
}
issueは上がっているのですが、postcss-nestedの前においても後ろにおいてもだめ。
やっているうちにprecss
をインポートして、postcss.config.jsにこの順序でコンパイルに成功しましたが、
'postcss-nested': {},
'precss':{},
'postcss-extend':{},
precssを入れるとcssファイルの@mediaがごっそり消えました。エラーが出てないのに@mediaの記述が消えるのは、何かおかしいということなので、extendでmixinネストを実現しようとするのは諦めました。
PostCSSに移行することによるメリットとデメリットの比較
あくまで自分のやりたいことを考えた時のメリットとデメリットです。
メリットは、なんとなく時代がそっち向いてそう…ということと、npm-scriptでglobが実現できるということ。
デメリットは、mixinのメディアクエリでネストができない、変数の計算ができない、mixinの中で変数が使えない。
今回dart-sassで疲れてもうやめようかなぁと考えていたのですが、とりあえずいけてる今、まだSassをやめるほど困っていないし、そう考えるとPostCSSに移行するデメリットの方が大きいような気がしてきました。
PostCSSにしたところで、「時代が変わればなにかしら更新」というのは、何を使っても一緒だし、今のところ普及率は同じくらいのような気がしています。
gulpをnpm-scriptにしようとも思いましたが、なんだかんだgulpも便利です。
パッケージがかなり豊富で、設定がgulpfile.js一枚でできて見通しがよく、Webサイト制作に向いた環境です。gulp依存が怖いという意見は最もですが、それ以上にnpm-scriptでSassのglobができないのは自分にとって結構なデメリットだし、じゃあPostCSSならできるかとやってみればその他に制約がある…ということで、自分の中で納得のいかない結果でした。
使うパッケージを変えるとあるいは…ですが(これでも結構探した)、現時点でわりと時間かけてこの程度ということは「今はその時じゃない」ということだと思い、移行は見送ることにしました。
まとめ
今回は、SassとPostCSSに加えてgulpとnpm-scriptの話がいっしょに出てきたので、何がしたいのかよくわからない印象になってしまったかもしれません。
実際、SassとPostCSSのことではなくgulpとnpm-scriptの話を書くつもりでした。…が、思った以上にPostCSSであれこれあったので、そちらにフォーカスした記事になりました。
今回移行をやめた理由は、それだけ見れば実はたいしたことじゃないです。mixinの中で変数が使えないのは致命的ですが、CSSカスタムプロパティを使うようにすれば可能で、全体的な作業効率は変わらないまま移行が可能だということがわかりました。
Web開発に関わるようになってから、npm-scriptは魅力的だなあと思うようになり、できればそっちを極めていきたいとも思ったので今回重い腰を上げてみましたが、やはり簡単にはいかないです。
今後また事情が変われば、考えてみようと思います。