[Sass(SCSS)]レスポンシブ対応。カラム数とカラム間marginを自由に設定するMixin

最近はCSSのフレームワークを利用する機会が増えましたが、フレームワークだと基本的にカラム間のmarginが固定されているので、ブロックまたはブレイクポイントによってmarginの値を変えたい時に不便に感じることがあります。
例えば、Bootstrapだと```$grid-gutter-width``` で設定した値が固定のmarginになります。

```scss:_variables.scss
$grid-gutter-width: 30px !default;
```

Bootstrap例

![bootstrap.png](https://qiita-image-store.s3.amazonaws.com/0/62022/bf6fb795-96bf-6832-69d5-12f48e9e06f3.png "bootstrap.png")

デザインによってはブロックごとにカラム間のmarginが違ったり、PCとスマートフォンでmarginを変えたかったり、フレームワークだと対応しきれないことが多いです。

そのためオリジナルのcssでブロック毎にスタイルを設定しなければならないのですが、都度カラム数に応じてwidthやmarginを書いていくのは面倒なので、mixinにまとめて記述量を減らそうと思います。

## 実現したいこと
- カラム数とカラム間marginを指定するcssを簡単に書きたい。
- 包括要素（.container）の左右端に子要素（.item）をピッタリ合わせる。
- 基本的にflexboxを採用するがfloatによる代替えも出来るようにしておく。

なお、基本的なHTMLの構造は以下のようになります。
親要素```.container```とは別に、カラムの包括要素```.row```を使用します。
比較しやすいようにBootstrapと同じclass名にしています。

```html
<div class="container">
	<div class="row">
		<p class="item">.item</p>
		<p class="item">.item</p>
		<p class="item">.item</p>
	</div><!-- /.row -->
</div><!-- /.container -->
```

![preview.png](https://qiita-image-store.s3.amazonaws.com/0/62022/cf939ebf-1f56-6aa7-718e-2f85fe28c8ba.png "preview.png")



## コード
### Sass(SCSS)

```scss
// clearfixのmixinを用意
@mixin clearfix{
	&:before,&:after { content: ""; display: table;}
	&:after {clear: both;}
	zoom: 1;
}

// こちらがカラム設定用Mixin
@mixin col(
	$column-count,
	$column-margin 	: margin(),
	$selector		: '.item',
	$is-list 		: false,
	$is-flex 		: true
) {

	// リストに適用する場合
	@if $is-list == true {
		$selector : '> li';
	}

	// is Flex (default)
	@if $is-flex == true {
		display: flex;
		flex-wrap: wrap;
		justify-content: space-between;

		$margin-size : #{$column-margin * ($column-count - 1)};

		#{$selector} {
			width: calc((100% - #{$margin-size}) / #{$column-count});
			@content;
		}
	} // end Flex

	// not Flex
	@else {
		@include clearfix;
		margin-left : #{-$column-margin};
		$margin-size : #{$column-margin * $column-count};

		#{$selector} {
			float: left;
			margin-right: -.1px;	// 小数点以下の切り捨て・切り上げ解釈違いに対応
			margin-left:#{$column-margin};
			width: calc((100% - #{$margin-size}) / #{$column-count});
			@content;
		}
	} // end if not Flex
}

// 書き方
// @include col(カラム数,margin値,'セレクタ');
```

### 使用例1 基本の使い方

- 包括要素：```.container```
- カラム数：3
- margin：40px
- カラムのセレクタ：```.item```
 
![3x40.png](https://qiita-image-store.s3.amazonaws.com/0/62022/035272ab-6ab3-9bc7-8678-db4df4e0d0df.png "3x40.png")


SCSS

```scss
.container {
	margin-right: auto;
	margin-left: auto;
	width: 800px;
}

.row {
	@include col(3,40px,'.item');
}
```

アウトプット後のCSS

```css
.container {
  margin-right: auto;
  margin-left: auto;
  width: 800px;
}

.row {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
}

.row .item {
  width: calc((100% - 80px) / 3);
}
```

### 使用例2 カラムに他のスタイルを追加する

- カラム数：4
- margin：15px
- カラムのセレクタ：```.item```
- ```.item``` にスタイルを追加

![4x15+style.png](https://qiita-image-store.s3.amazonaws.com/0/62022/5eb6a1a6-1ef8-7db4-fcae-73696d1986e0.png "4x15+style.png")

SCSS

```scss
.row {
	@include col(4,15px,'.item') {
		background-color: #fff;
		color: #6BC9FF;
	}
}
```

```.item``` にスタイルを追加する場合は  ```@include col(4,15px,'.item') { // ここに記入 }``` このようにカッコ内に書きます。

アウトプット後のCSS

```css
.row {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
}

.row .item {
  width: calc((100% - 45px) / 4);
  
  /* 追加したスタイル */
  background-color: #fff;
  color: #6bc9ff;
}
```



### 使用例3 リストに使用する

- カラム数：3
- margin：40px
- カラムのセレクタ：```> li```

SCSS

```scss
.row {
	@include col(3,40px,$is-list:true);
}
```

セレクタを指定しない代わりに ```$is-list:true``` を指定します。

アウトプット後のCSS

```css
.row {
  display: flex;
  justify-content: space-between;
  margin-top: 0;
  margin-bottom: 0;
  flex-wrap: wrap;
}

.row > li {
  width: calc((100% - 80px) / 3);
}
```

### 使用例4 Flexboxではなくfloatで実装する

- floatを使う
- カラム数：3
- margin：40px
- カラムのセレクタ：```.item```

SCSS

```scss
.row {
	@include col(4,20px,'.item',$is-flex:false);
}
```

アウトプット後のCSS

```css
.row {
  margin-left: -20px;
}

.row::after {
  content: '';
  display: table;
  clear: both;
}

.row .item {
  float: left;
  margin-right: -.1px;
  margin-left: 20px;
  width: calc((100% - 80px) / 4);
}
```

```.row``` にマイナスマージンを入れることで```.container``` の左右端に```.item``` を合わせています。
なので、基本的には背景や幅を指定するclassは```.container``` になり、```.row``` はあくまでもレイアウト用のclassになります。

![4x15float.png](https://qiita-image-store.s3.amazonaws.com/0/62022/b8923b53-d3a9-5d55-215c-117ad0f4eb77.png "4x15float.png")


### 使用例5 メディアクエリ内で使用

SCSS

```scss
.row {
	@media screen and (min-width: 768px) {
		@include col(3,30px,'.item');
	}
}
```

アウトプット後のCSS

```css
@media screen and (min-width: 768px) {
  .row {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
  }
  
  .row .item {
    width: calc((100% - 60px) / 3);
  }
}

```

---

以上になります。

包括要素（.row）が必要にはなりますが、カラム間marginまで設定できるのは他のフレームワークではあまり無いように感じたので、結構便利に使っています。

参考になりましたら幸いです。