Railsで複数のSass(.scssファイル)を使用する際の読み込み方法


はじめに

RailsでSassを使用し、かつファイルを用途・適応範囲に応じて複数に分割したとき、どのような構成、読み込み方式にするかを実際の失敗談交えながら、記載したいと思います。
最初に「つまづいたこと」で、私が体験した発生した事象や原因などを書いていますが、必要なければ読み飛ばしてもらえればと思います。

環境

ruby: 2.6.4
rails: Rails 6.0.3.1 (sass-rails gemを使用)

まず結論

Railsで複数のSassを使用する際には、読み込みをSprocketsディレクティブ方式(require_tree)ではなく、@importで読み込むこと

つまづいたこと

携わったプロジェクトではSassを使用しており、かつスタイルファイルをメンテしやすくするため、コントローラ単位で.scssファイルを作成していた。
stylesheets直下のapplication.scssで全体に共通のスタイルを設定し、stylesheets/main配下に複数の.scssファイルを配置。

application.scssでは、以下の内容を記載していた。
1. ディレクティブ方式でmain配下のscssファイルを読み込み
2. その後bootstrapなどを読み込み(@import )
3. 最後に共通スタイルを設定。

application.scss
 中略 
 *= require_tree ./main 
 *= require_self     *= require_self
 */  

@import "bootstrap/scss/bootstrap";

 中略 
// 共通スタイル
body {  
  font-family: ....
}
 中略 

やろうとしたこと

今回、共通で使用する変数 (ex $main-color: #3D85C6;)を作成して、各.scssファイルで使い回そうと思い、以下のように共通変数の定義を追記した。

application.scss(改修後)
〜 中略 〜
 *= require_tree ./main 
 *= require_self     *= require_self
 */  

@import "bootstrap/scss/bootstrap";

〜 中略 〜

// 共通変数
$main-color: #3D85C6;   

// 共通スタイル
body {  
  font-family: ....
}
〜 中略 〜

ただ、この状態だとmain配下のscssファイルで変数を使用するとエラーになったため、変数の読み込みが必要だと思い、main配下のscssファイル側でapplication.scss@importした(今思えば、なぜこんな書き方をしたのか、後悔しかない・・・)
結果、main配下のscssファイルでも、変数を使用でき、スタイルも適用されてめでたしめでたしと思っていました。

その後、起こったこと

カスタマイズを進め、applicaiton.scssに変更を加えていく中で、不可解な現象が、、、

  • ブラウザの検証機能でスタイルを見ると、同じスタイルが2つある
  • application.scss内のとあるクラスのスタイルから、一部プロパティを削除しても反映されない (前述のとおり同一スタイルが2つ存在し、片方しかプロパティ削除が反映されていない)

原因

すでにお気づきかもしれませんが、「やろうとしたこと」の中で、main配下のscssファイルで、application.scssをimportしてしまったたため、
そこに記載したスタイルが二重で読み込まれてしまいました。なおかつapplication.scssでimportしたbootstrap関連のscssも二重で読み込まれてました。
ただ、applicaiton.scss内のスタイルを変更しても、反映されない原因は結局わからず・・

というわけで、main配下のscssでのimportを削除するとともに、railsで複数のscssファイルを利用するためには、どのような読み込み方法良いのか調べることになりました。。

railsで複数のscssファイルを利用際の適切な読み込み方法

調査した結果

railsguide, rails-sass(gem)のページに記載の通り、railsで複数のSass(.scssファイル)を使用する際には、Sprocketsディレクティブで読み込まずにSass@importルールを使用する必要があります。

ディレクティブ方式だと、宣言した変数やmixinが他のscssファイルから利用できない。(まさしく今回私が体験した内容)

Sassファイルを複数使用しているのであれば、Sprocketsディレクティブで読み込まずにSass @importルールを使用する必要があります。このような場合にSprocketsディレクティブを使用してしまうと、Sassファイルが自分自身のスコープに置かれるため、その中で定義されている変数やミックスインが他のSassから利用できなくなってしまいます。

Important Note
Sprockets provides some directives that are placed inside of comments called require, require_tree, and require_self. DO NOT USE THEM IN YOUR SASS/SCSS FILES. They are very primitive and do not work well with Sass files. Instead, use Sass's native @import directive which sass-rails has customized to integrate with the conventions of your Rails projects.

最終的なapplicaiton.scssの記載内容

最終的には以下のような記述内容にしました。
これにより、common.scssで定義した変数が他のmain配下のscssファイルでも読み込むことができました。

  • applicaiton.scssから、reuire_tree, require_selfの記載を削除
  • 元々applicaiton.scssに記載していた共通スタイルと変数は、common.scssを新たに作成して移管
  • @importでcommon(共通スタイル)、main配下のスタイルを順に読み込み
application.scss(最終)
〜 中略 〜
 *      
 */

@import "bootstrap/scss/bootstrap";

@import "common";
@import "main/*";

参考文献

あるべきscssファイルの取り込み方法を理解するために大変参考になりました。

rails/sass-rails

アセットパイプライン - Railsガイド