クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【Sass(SCSS)】変数($)、@mixinを使ってモジュールを超えた共通スタイルを設定する

メタ言語の続きです。前回はSass(SCSS)の@importを使ってBEMのブロックごとにファイルを分けました。今回は変数($)や@mixinを使って、モジュールファイルを超えた共通スタイルを設定してみます。それではいきましょう!

【目次】

※参考:前回記事
【Sass(SCSS)】@importでBEMのBlockごとにファイル分割する - クモのようにコツコツと

※メタ言語(HTMLテンプレートエンジン、AltCSS、AltJS)まとめ qiita.com

前回のおさらい

前回、BEMのブロックごとに「_ブロック名.scss」という名のモジュールファイルに分割。全体共通部分の「_base.scss」も作成。
f:id:idr_zz:20200522192252j:plain

ファイル名の頭にアンスコ_を付けると「パーシャル」ファイルとしてコンパイル時に無視される。cssフォルダには本体の「style.css」しかコンパイルれない。 f:id:idr_zz:20200530062559j:plain

そしてパーシャルを@importで本体の「style.scss」にインポートするとコンパイル時に読み込まれて合体する。

これによって、ブロックの名前がファインダーで一目瞭然になり、ブロック名が重複する心配もなくなる。

詳細は前回の記事を参照。

※参考:【Sass(SCSS)】@importでBEMのBlockごとにファイル分割する - クモのようにコツコツと

変数($)に共通スタイルの値を設定

変数の書き方

ただ、この状態で作って行った時に、同じような設定のスタイルがモジュールファイルを超えて分散し、修正が大変になりそうな予感がする。

Sass(SCSS)にはそれを解決する方法がある。まずは変数を使ってみたい。

Sass(SCSS)の変数は以前、「CSS変数」の記事でも触れた。*1

※参考:CSS変数でドット絵マリオをルイージにしたった! - クモのようにコツコツと

このような書き方。

/*SCSS変数定義*/
$変数名: 値;
  • 変数名の頭にドル$を付ける。

※参考:Sass: Variables

_variable.scssを作成

「setting」というフォルダを作ってその中に「_variable.scss」を作成。
f:id:idr_zz:20200530062421j:plain

ひとまず色関係の変数を設定してみる。

_variable.scss

$base-color: #C30D23;
$text-color: #333;
$text-color_w: #fff;
$bg-color_g: #eee;

それを本体のstyle.scssにインポート。前回の@importを使う。

@import 'setting/_variable';

/***** base *****/
@import 'base/_base';


/***** block *****/
@import 'block/_main';
@import 'block/_inner';

記述順にコンパイルされるので_variableは一番上にしてみる。コメントを付けるとコンパイルされてしまうため、コメント無しにしている。

ブロックの色設定を変数に置き換える

各ブロックの色スタイルを変数に置き換えてみる。

_base.secc

body {
    margin: 0;
    padding: 0;
    font-family: sans-serif;
    color: $text-color;
    a {
        color: $base-color;
    }
}

_main.scss

/* main */
.main {
    width: 960px;
    margin: 0 auto;
    &__title {
      color: $text-color;
      font-size: 2em;
    }
    &__lede {
      font-size: 1em;
    }
  }

_inner.scss

/* inner */
.inner {
    margin: 0 0 40px;
    &__title {
      padding: 10px;
      background: $bg-color_g;
      border-left: 2px solid $base-color;
      font-size: 1.5em;
      line-height: 1.2;
      }
     &__text {
      &-em {
        font-weight: bold;
        background: $bg-color_g;
        padding: 5px;
        color: $base-color;
      }
      &-bikou {
      font-size: 0.8em;
      &:before {
          content: "※";
        }
      }
      &-btn {
        background: $base-color;
        color: $text-color_w;
        padding: 10px;
      }  
    }
  }

コンパイル結果

これでどうコンパイルされるか確認する。

gulp起動!

npx gulp

ブラウザ立ち上がる。見た目は変わらない! f:id:idr_zz:20200522182239j:plain

コンパイルされたCSSも前回と同じ!

style.css

@charset "UTF-8";
/***** base *****/
body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  color: #333;
}

body a {
  color: #C30D23;
}

/***** block *****/
/* main */
.main {
  width: 960px;
  margin: 0 auto;
}

.main__title {
  color: #333;
  font-size: 2em;
}

.main__lede {
  font-size: 1em;
}

/* inner */
.inner {
  margin: 0 0 40px;
}

.inner__title {
  padding: 10px;
  background: #eee;
  border-left: 2px solid #C30D23;
  font-size: 1.5em;
  line-height: 1.2;
}

.inner__text-em {
  font-weight: bold;
  background: #eee;
  padding: 5px;
  color: #C30D23;
}

.inner__text-bikou {
  font-size: 0.8em;
}

.inner__text-bikou:before {
  content: "※";
}

.inner__text-btn {
  background: #C30D23;
  color: #fff;
  padding: 10px;
}

Sass(SCSS)の変数はファイルを超えても適用されることがわかった!

@mixinで再利用するスタイルを定義

@mixinの書き方

次に@mixinを使って再利用するスタイルの定義をしてみる。

※参考:Sass: @mixin and @include

先程の変数はCSSの「値」の部分を置き換えたが、@mixinはプロパティと値のセットで設定できる。

@mixinこんな書き方

@mixin mixin名 {
  プロパティ1: 値;
  プロパティ2: 値;
  プロパティ3: 値;
}

@includeで読み込む。@mixinとセットの存在。

セレクタ {
  @include mixin名;
  プロパティ4: 値;
  プロパティ5: 値;
}

コンパイル結果

セレクタ {
  プロパティ1: 値;
  プロパティ2: 値;
  プロパティ3: 値;
  プロパティ4: 値;
  プロパティ5: 値;
}

mixinのスタイルも一緒にコンパイルされる

引数を使った@mixin

関数のように引数を使うこともできる。

@mixin mixin名($引数1, $引数2) {
  プロパティ1: $引数1;
  プロパティ2: $引数2;
  プロパティ3: 値;
}

@includeで読み込む時に引数の値を設定すると

セレクタ {
  @include mixin名(#fff, 10px);
  プロパティ4: 値;
  プロパティ5: 値;
}

コンパイル結果

セレクタ {
  プロパティ1: #fff;
  プロパティ2: 10px;
  プロパティ3: 値;
  プロパティ4: 値;
  プロパティ5: 値;
}

引数が反映されている。

引数に初期値を設定する

コロンで繋いで値を入れると引数の初期値になる

@mixin mixin名($引数1:#fff, $引数2:10px) {
  プロパティ1: $引数1;
  プロパティ2: $引数2;
  プロパティ3: 値;
}

@includeでインクルードする時に引数空欄だと初期値が入る

/*引数空欄*/
セレクタ1 {
  @include mixin名();
  プロパティ4: 値;
  プロパティ5: 値;
}

コンパイル結果

/*引数空欄*/
セレクタ1 {
  プロパティ1: #fff;
  プロパティ2: 10px;
  プロパティ3: 値;
  プロパティ4: 値;
  プロパティ5: 値;
}

引数の上書き(全て)

インクルード時に引数を入力すると値が上書きされる

/*引数上書き(全て)*/
セレクタ2 {
  @include mixin名(#ccc, 30px);
  プロパティ4: 値;
  プロパティ5: 値;
}

コンパイル結果

/*引数上書き(全て)*/
セレクタ2 {
  プロパティ1: #ccc;
  プロパティ2: 30px;
  プロパティ3: 値;
  プロパティ4: 値;
  プロパティ5: 値;
}

引数の上書き(一部)

引数を一部上書きしたい場合は引数名も書く

/*引数上書き(一部)*/
セレクタ3 {
  @include mixin名($引数2:30px);
  プロパティ4: 値;
  プロパティ5: 値;
}

コンパイル結果

/*引数上書き(一部)*/
セレクタ3 {
  プロパティ1: #fff;
  プロパティ2: 30px;
  プロパティ3: 値;
  プロパティ4: 値;
  プロパティ5: 値;
}

mixinを実装してみる

_mixin.scssを作成

実際にやってみる。まず「setting」フォルダに「_mixin.scss」を作成。
f:id:idr_zz:20200530080408j:plain

「style.scss」で「_mixin.scss」をインポート

@import 'setting/_variable';
@import 'setting/_mixin';

/***** base *****/
@import 'base/_base';


/***** block *****/
@import 'block/_main';
@import 'block/_inner';

_mixin.scssでflexboxのmixinを設定

@mixinはflexboxとかpositonとかbackgroundとか、複数個のプロパティで指定するスタイルなんかに使うと便利そう。

例えばこの下の方の「ここ押せワンワン」ボタンをflexboxで真ん中寄せにしてみる。 f:id:idr_zz:20200522182239j:plain

「_mixin.scss」にflexboxの設定を書く。

@mixin flexbox($wrap: nowrap, $justify: flex-start, $align: stretch) {
    display: flex;
    flex-wrap: $wrap;
    justify-content: $justify;
    align-items: $align;
}
  • mixin名はflexbox()
  • flexbox()の引数は左から$wrap, $justify, $align
  • 引数$wrapの初期値はnowrap
  • 引数$justifyの初期値はflex-start
  • 引数$alignの初期値はstretch
  • スタイルの値に3つの引数を設定

index.ejsにflexboxを設定するdivタグを追加

「index.ejs」のボタン部分はfor文の中の. inner__textに読み込まれている変数inner

       <% for (var i = 0; i < inner.length; i++) { %>
            <section id="nest" class="inner">
                <h2 class="inner__title"><%- inner[i].title %></h2>
                <p class="inner__text"><%- inner[i].text %></p>
              </section>  
        <% } %>

EJSの設定についてはこちらを参照

※参考:【メタ言語】BEMによるclass名をSass(SCSS)とEJSで書いてみる(モジュール事始め) - クモのようにコツコツと

変数innerdivタグを追記する。class名は.inner__text-flexとする。

   let inner = [
        // 中略
        {
        title:'TypeScriptで書いたクリックイベント',
        text: '<div class="inner__text-flex"><button class="inner__text-btn">ここ押せワンワン</button></div>'
        }
    ]

_inner.scssにflexboxをインクルード

-btnの手前に-flexを追記。

_inner.scss

.inner {
  /* 中略 */
      &-flex {
        @include flexbox($justify: center);
      }
      &-btn {
        background: $base-color;
        color: $text-color_w;
        padding: 10px;
      }  
    }
  }
  • -flexflexboxをインクルード。変数$justifycenterに設定

コンパイル結果

ブラウザがリロードされてボタンがセンター寄せになった! f:id:idr_zz:20200530092242j:plain

コンパイル結果

index.html

<section id="nest" class="inner">
    <h2 class="inner__title">TypeScriptで書いたクリックイベント</h2>
    <p class="inner__text"><div class="inner__text-flex"><button class="inner__text-btn">ここ押せワンワン</button></div></p>
</section>
  • .inner__textの中に.inner__text-flexが追加されている

style.css

.inner__text-flex {
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  align-items: stretch;
}

.inner__text-btn {
  background: #C30D23;
  color: #fff;
  padding: 10px;
}
  • .inner__text-flexが追加され、justify-contenにはcenter、それ以外は初期値が入っている

おまけ:@mixinと似ている@extend(スタイルの継承)

@mixinと似た機能で@extendというのもある。extendは「継承」という意味。

@mixinのような設定部分はなく、セレクタのスタイルをそのまま継承する。

セレクタ1 {
  プロパティ1:値;
}

セレクタ2 {
  @extend .セレクタ1;
  プロパティ2:値;
}

@mixinでの@includeと同じ位置づけ。

コンパイルすると継承元にグループ化されるのが@mixinと異なる。

セレクタ1, セレクタ2 {
  プロパティ1:値;
}

セレクタ2 {
  プロパティ2:値;
}

あと、@mixinのような引数はない。

@mixin@extendの使い分け方など、こちらの記事がわかりやすかった。

※参考:Sassの「@mixinと@extendの違い」と使い分け

最後に

f:id:idr_zz:20200530092242j:plain

モジュールをファイルで分けると共通スタイルの見通しが悪くなる、と感じてたんですが、変数$@mixinを使えばそれも解消しますね!

ファイルをまたがる設定は「_setting」など別フォルダにしてその中で管理していけばいいと思いました。

ファイル名、フォルダ名などは色々な流儀があり、開発規模によっても変わってくると思います。自分も試行錯誤して行きたく思います。

次回はEJSファイルの方もモジュール分割してみたく思います。それではまた!


※メタ言語(HTMLテンプレートエンジン、AltCSS、AltJS)まとめ qiita.com

*1:昔はネイティブCSSには変数はなかったが、AltCSSの変数が好評だったため正式に採用された、という流れがある