Bootstrap4とSCSSでの開発手法の模索

## はじめに
 
Bootstrap4が徐々に流行り始め、IEのサポート終了と共に、Gridシステムにflexが当たり前に使われるようになる時代が来ようとしています。

多くのフレームワークでSCSSなどといったメタ言語を利用できる今、それを利用し開発するフロントエンドエンジニアが多くいると思います。メタ言語を使うことによって高度化し抽象化されたStyleSheetは、一度方針を決めたら手戻ししにくい、諸刃の剣にもなってしまいました。そんなデザインマークアップにも設計書が必要な時代に、Bootstrap4とSCSSを用いた最良な開発手法とは何かを模索したものが本記事です。個人的に気に入った書き方とルールを随時載せていくので、ストックしておくと良いかもしれません。

## Bootstrap3から4への移行

### Global changes

#### Flexboxの採用

> - Flexbox is enabled by default. In general this means a move away from floats and more across our components.

 `Flexbox`が標準採用されるようになりました。これによってレイアウト配置の幅が効くようになり、今まで手が届かなかった痒いところに手が届くようになりました。

#### LessからSassに

> - Switched from Less to Sass for our source CSS files.

Bootstrap本体のメタ言語が Less から Sass に変わりました。今までありがとうLess…・

#### サイズ単位の変更
 
> - Switched from px to rem as our primary CSS unit, though pixels are still used for media queries and grid behavior as device viewports are not affected by type size.


CSSのサイズ単位が`px`から`rem`に変わりました。`rem`はルート要素のfont-sizeとの比なのでルートのフォントサイズを変えることによって、デバイスによるサイズ変更に柔軟に対応できるようになりました。

#### デフォルトフォントのサイズアップ

> - Global font-size increased from 14px to 16px.

スマートフォンが大きくなるのに合わせ、デフォルトのフォントサイズも大きくなりましたね。

#### 新たなブレークポイントの追加、-xsの廃止

> - Revamped grid tiers to add a fifth option (addressing smaller devices at 576px and below) and removed the -xs infix from those classes. Example: .col-6.col-sm-4.col-md-3.

Breakpointが増えました。また、`-xs`が廃止になり、`col-xs-*`は`col-*`と表記するようになりました。

#### 新たなUtilityクラスの追加

> - Added dozens of new utility classes for common CSS property-value pairs and margin/padding spacing shortcuts.
 
utilityクラスが増えました。`padding` や `margin` といった、余白を取り扱う時に `{property}{sides}-{breakpoint}-{size} ` をクラス指定することによって余白を取ることができるのは大きいですね。`mt-2`とクラス指定してあげれば`margin-top: $spacer * 0.5rem;`の余白を取ることができます。

#### その他割愛

> - Replaced the separate optional theme with configurable options via SCSS variables (e.g., $enable-gradients: true).

> - Build system overhauled to use a series of npm scripts instead of Grunt. See package.json for all scripts, or our project readme for local development needs.

> - Non-responsive usage of Bootstrap is no longer supported.

> - Dropped the online Customizer in favor of more extensive setup documentation and customized builds.

実装自体に大きな影響は及ぼさないので、割愛します。

## 最適解へのアプローチ

色々触ってみて、個人的に一番良いと思った記述方法について書きます。

### ルール

#### レイアウトを定義するSCSSは極力書かない

> レイアウトの配置にまつわる大半が、Bootstrapが提供する機能で解決できます。`col`によるオートレイアウトはかなり汎用性の高い機能です。解決できない場合は、Bootstrapを深く読み込んでいないか、アンチパターンのデザイン実装を試みていると思ってください。
 
#### コンポーネントは分割する

> コンポーネントは、SCSSの@importを使いファイルを分割しましょう。HTMLのマークアップでとても大切なことは、塊(コンポーネント)を意識することです。コンポーネントを組み合わせることによって、一つのページができていると考えると、汎用的なSCSSを書くことができるようになります。

#### Utilityを駆使する

> Bootstrap3の時代は、rowやcolのgutter(paddingによってとられる余白)に悩まされていたと思います。Bootstrap4では、Utilityにspacingにまつわる記述がサポートされているかつ、flexboxで実装されていることから、breakpointに合わせての余白変更や、縦並び <-> 横並びの表現変更、水平方向や垂直方向でのアラインメントも全てHTMLマークアップのみで実現できます。

#### 変数を駆使する

> colorなどを値として書かれると、後から見た人はそれがなんなのかを理解するためにdeveloperツールとエディタを行き来しなければなりません。なので、変数としてまとめ、それを@importして利用するようにしましょう。 

```variables.scss
$base-theme-color: #fff; //メインカラー
$base-hover-color: #f7f7f7; //ホバーカラー
$sub-theme-color: #B1B1B1; //サブカラー
$accent-theme-color: #F96332; //アクセントカラー
$base-text-color: #333; //ベースのフォント色
$inactive-text-color: #B1B1B1; //インアクティブなフォント色

-----------------------
@import "path/to/variales.scss";

.hoge {
  color: $base-theme-color;
}
```



### 単位は %, vw, vh, rem で縛る

> 基本的に、単位は上記のもののみを使うようにします。divのサイズなどを指定するときも、remを使用します。そうすることによって、全ての要素が、基準値に従って変わるようになります。他の単位を使ったら、寿命が一年減ると思ってください。


### `@mixin`を駆使する

> mixinを駆使しましょう。mixinは神が与えてくれたとても便利な機能です。mixin.scssのようなファイルに関数をまとめておき、importして使うようにしましょう。

```scss
@mixin position($position, $top: null, $right: null, $bottom: null, $left: null) {
  position: $position;
  top: $top;
  right: $right;
  bottom: $bottom;
  left: $left;
}

@mixin absolute($args...) {
  @include position(absolute, $args...);
}

@mixin relative($args...) {
  @include position(relative, $args...);
}

@mixin fixed($args...) {
  @include position(fixed, $args...);
}

---------------------------------------------
.bar {
	@include position(absolute, $top: 2em, $left: 10%);
}

=>

.bar {
  position: absolute;
  top: 2em;
  left: 10%;
}
```

```scss
$set-prefix: '' , -moz- , -webkit-;

@mixin vendorPrefix($name, $value) {
    @each $prefix in $set-prefix {
        #{$prefix}#{$name}: $value;
    }
}
---------------------------------------------
.foo {
	@include vendorPrefix(transition, background-color 0.2s linear);
}

=>

.foo {
  transition: background-color 0.2s linear;
  -moz-transition: background-color 0.2s linear;
  -webkit-transition: background-color 0.2s linear;
}
```

### breakpointと向き合う

> bootstrapと付き合っていく上で、一番難しいのはbreakpointとの付き合い方です。bootstrapは、レイアウトを変えてくれる反面、それに合わせてフォントサイズやデザインを調整する必要があります。bootstrap4になってからは、spacingの対応はHTMLマークアップで解決できるようになりましたが、フォントにまつわるサイズ調整や諸々は、まだrootのサイズを変えるだけでは不十分だと思いました。そのため、私はその問題を変数とmixinによって解決しています。

```scss
@import "../../helpers/variables.scss";
@import "../../helpers/mixin.scss";

@mixin styling-dashboard($dashboard-base-scale) {
  #dashobard {
    .feed-title {
      .nav .nav-item .nav-link {
        color: $inactive-text-color;
        &.active {
          font-weight: bold;
          color: $base-text-color;
          border-bottom: $dashboard-base-scale * 0.2rem solid $base-text-color;
        }
      }
    }
    .tags {
      .tag {
        border-radius: $dashboard-base-scale * 1.8rem;
        font-size: $dashboard-base-scale * 0.8rem;
        border: $dashboard-base-scale * 0.05rem solid $base-text-color;
        padding: $dashboard-base-scale * 0.3rem $dashboard-base-scale * 1rem;
      }
    }
    article {
      @include vendorPrefix(transition, background-color 0.2s linear);
      &:hover {
        background-color: $base-hover-color;
      }
      h3 {
        font-size: $dashboard-base-scale * 1.4rem;
      }
      .author_icon {
        width: $dashboard-base-scale * 1.4rem;
        height: $dashboard-base-scale * 1.4rem;
        background-size: cover;
      }
    }
  }
}

@include styling-dashboard($dashboard-base-scale: 1.0);

@media (min-width: 576px) {
  @include styling-dashboard($dashboard-base-scale: 1.0);
}

@media (min-width: 768px) {
  @include styling-dashboard($dashboard-base-scale: 0.9);
}

@media (min-width: 992px) {
  @include styling-dashboard($dashboard-base-scale: 1.0);
}

@media (min-width: 1200px) {
  @include styling-dashboard($dashboard-base-scale: 1.1);
}

@media (min-width: 1400px) {
  @include styling-dashboard($dashboard-base-scale: 1.3);
}


```

> この書き方はベストではなく、ベターでしょう。ただ、他の書き方もいまいちピンとこないので、アイデアがあればコメントよろしくお願いします。
 
## 最後に 

これはあくまで、私なりに考えた最良の開発手法です。もちろんこれが至高ではないと思います。みなさんのアイデアで、より良いものにしていきたいので、ぜひコメントお願いします！