HTML5
CSS3
scss
Design
bootstrap

そろそろBootstrapを卒業しようと思う[グリッドシステム編]

卒業する前に。

便利故に何でもかんでもBootstrapを使えばいいみたいな風潮になってきている(私の中で)のでBootstrapを使わずにスタイルを組み立ててみようと思い、記録用に記事にします。

▪投稿者のスペック
デザイナーとして、画像制作・編集を担当する傍ら、メインコーダーのサブとしてコーディングをサポートしています。
JavaScript(jQuery)とSASSは現在勉強中。5割程度しか使えていないと思います。
実務経験は2年。今回の記事に間違いが混じっていることがあるかと思います。
その時はご指摘頂きますと、とても嬉しく思います。

グリッドシステムの仕組みを理解する

glidsystem.jpg
Bootstrapのグリッドシステムはwidth100%を12分したもの
width:50%を取りたい場合、12の半分で6 '.col-md-6'というクラス名でしたね。

これを噛み砕くとこんな計算式になります。
100% ÷ (12 ÷ 6) = 50%
100% × 6 ÷ 12 = 50%

CSSに表すと以下のようになります。

glid.css
.col-6{
  width: calc(100% * 6 / 12);
}

SASS(SCSS)でイクルード出来るように、ミックスインを作りましょう。

glid.scss
@mixin col($nam) {
  width: (100% * $nam / 12);
}

これを1〜12の各クラスのPC用とスマホ用に量産します。
指定数の量産は'@for'文を使います。
'@for'文ではクラス名の指定に変数から引用できます。
その際、呼び出す変数は、'#{$}'で囲ってあげます。

glid.scss
@mixin col($nam) {
  width: (100% * $nam / 12);
}

@for $nam from 1 through 12{
  .col-pc-#{$nam}{
    @include col($nam);
  }
}

@media screen and (max-width: 724px){
  @for $nam from 1 through 12{
    .col-sp-#{$nam}{
      @include col($nam);
    }
  }
}

.l-row{
  display: flex;
  flex-wrap: wrap;
}

colクラスだけでは、一列に整列してくれないので、親ブロックにはdisplay:flexをかけてます。スマホで改行させたいときのために'flex-wrap'も忘れずに。
基本はこのカタチで'padding','margin'有り無しに合わせてカスタマイズしていきます。
'padding'有りの場合、'@mixin col'の中身を書き換えてあげましょう。

padding有りの場合

glid.scss
@mixin col($nam,$col-pd) {
  width: 100% * $nam / 12;
  padding:0 $col-pd;
  box-sizing: border-box;
}

box-sizingを追加して、paddingとborderも合わせたwidthを取得するように設定します。

marginもpaddingも有り

glid.scss
$col-mg: 10px;
$col-pd: 20px;

@mixin col($nam,$col-mg,$col-pd) {
  width: calc(100% * #{$nam} / 12 - #{$col-mg}*2);
  margin:0 $col-mg;
  padding:0 $col-pd;
  box-sizing: border-box;
  background: #333;
}

@for $nam from 1 through 12{
  .col-pc-#{$nam}{
    @include col($nam,$col-mg,$col-pd);
  }
}
@media screen and (max-width: 724px){
  @for $nam from 1 through 12{
    .col-sp-#{$nam}{
      @include col($nam,$col-mg,$col-pd);
    }
  }
}

.l-row{
  display: flex;
  flex-wrap: wrap;
}

SASSでは%とpxの計算は合わせて出来ないため'clac()'で囲ってあげないといけません。

エラー例.
× width:(100% * $nam / 12) - $col-mg*2;
//この文ではエラーが発生します。

'clac()' と'@mixin'を併用する場合、変数は'@for'と同様に'#{$}'の中に入れてあげると読み込んでくれます。
大まかにご紹介しましたが、基本のグリッドスタイルについて以上です。
以下より、関数をおりまぜて、扱いやすいスタイルに改良していきます。

配列・読み込み用関数を用意する

glid.scss
$col:( //grid
  mg-pc : (0,10px),
  mg-sp : (0,10px),
  pd-pc : (0,20px),
  pd-sp : (0,20px)
);
// @debug map-get($col,mg-pc);

@function gMap($name,$prf,$scr){
  $i : map-get($col, $prf);
  $i : nth($i,$scr);
  @return $i;
}
//@debug gMap($col,mg,2) //...10px

$colという連想配列にmarginpaddingを設置し直します。
この値を読み込む用の関数 gMap()を作ります。
$name配列の$prfの要素が持つ、$scr番目の値を返すという関数です。

関数を利用する

glid.scss
@function col-calc($num,$name){
  $margin : gMap($col,#{$name},2);
  $i: calc(100% * #{$num} / 12 - #{$margin} * 2);
  @return $i;
}

.pc-col-style{
  margin: gMap($col,mg-pc,1) gMap($col,mg-pc,2);
  padding:  gMap($col,pd-sp,1) gMap($col,pd-sp,2);
  box-sizing: border-box;
}
  box-sizing: border-box;
}

@mixin col($num,$name) {
  width: col-calc(#{$num},#{$name});
}

@for $num from 1 through 12{
  .l-pc-#{$num}{
    @include col($num,mg-pc);
    @extend .pc-col-style;
  }
}
@media screen and (max-width: 724px){
  .sp-col-style{
    margin: gMap($col,mg-sp,1) gMap($col,mg-sp,2);
    padding:  gMap($col,pd-sp,1) gMap($col,pd-sp,2);
    box-sizing: border-box;
  }
  @for $num from 1 through 12{
    .l-sp-#{$num}{
      @include col($num,mg-sp);
      @extend .sp-col-style;
    }
  }
}

col-calc()関数は上述の
calc(100% * #{$nam} / 12 - #{$col-mg}*2);と同じ処理を行います。
各グリッドのmarginとpaddingを一つの配列で管理するスタイルに変更したので関数で扱いやすいように書き換えてあげました。
@extend .col-style で同じスタイルはまとめてコンパイルしてあげます。

containerを追加する

grid.scss
.l-container{
  padding:{
    top: 75px;
    right: 6%;
    bottom: 80px;
    left: 6%;
  }
index.html
<div class="l-container">
  <div class="l-row">
    <div class="l-pc-3">test</div>
    <div class="l-pc-3">test</div>
    <div class="l-pc-3">test</div>
    <div class="l-pc-3">test</div>
  </div>
</div>

.containerで全体のレイアウトを調整します。
ss.jpg
上記のようなレイアウトが完成します。

両端を揃える

grid.scss
$col:(//grid
  mg-pc : (0,10px),
  mg-sp : (0,0px),
  pd-pc : (0,20px),
  pd-sp : (0,20px),
  row-pc: (0,-10px) //←ココを追加
);

@function gMap-col($prf){
  $i : map-get($col,$prf);
  $str1 : nth($i,1);
  $str2 : nth($i,2);
  @return $str1 $str2;
}
//@debug gMap-col(row-pc);

.l-row{
  display: flex;
  flex-wrap: wrap;
  margin: gMap-col(row-pc); //←ココを追加
}

colクラスにおける左右marginの影響で余分な空白がうまれるので、
.rowからネガティブマージンで両端を調整します。

inner rowを整える

以下のソースコードのようにグリッドの中にグリッドを入れたい時があります。

index.html
<div class="l-pc-12">
  <div class="l-row">
    <div class="l-pc-6"></div>
    <div class="l-pc-6"></div>
  </div>
</div>

その場合rowのmargiが邪魔をしてwidthに影響を及ぼします。
対処としてl-row内のmarginを調整します。

grid.scss
   .l-row{
     display: flex;
     flex-wrap: wrap;
     @include media(MED(f3)){
       // margin: gMap-col(row-pc);
     };
    .l-row{
     margin: gMap-col(row-pc);
    }
   }

以下、最終コード

grid.scss
/*code / fuction*/
$setMedia:(//media query
  f0 : 1170px,
  f1 : 960px,
  f2 : 720px,
  f3 : 540px
);
@function MED($num) {
  $i : map-get($setMedia, $num);
  @return $i;
}

$col:(//grid
  mg-pc : (0,12.5px),
  mg-sp : (0,0px),
  pd-pc : (0,20px),
  pd-sp : (0,20px),
  row-pc: (0,-12.5px)
);
// @debug map-get($col,mg);
@function gMap($name,$prf,$scr){
  $i : map-get($name, $prf);
  $i : nth($i,$scr);
  @return $i;
}
@function gMap-col($prf){
  $i : map-get($col,$prf);
  $str1 : nth($i,1);
  $str2 : nth($i,2);
  @return $str1 $str2;
}
// @debug gMap-col(row-pc);
//@debug gMap($col,mg,2) //...10px

@function col-calc($num,$name){
  $margin : gMap($col,#{$name},2);
  $i: calc(100% * #{$num} / 12 - #{$margin} * 2);
  @return $i;
}

/* layout
  ========================================================================== */
@mixin media($width){
  @media screen and (max-width: $width){//$width以上の場合適応
    @content;//@include media(MED($num)){style}
  }
}
   //<=========== 以下grid_system ===========>
   .pc-col-style{
     margin: gMap-col(mg-pc);
     padding: gMap-col(pd-pc);
     box-sizing: border-box;
   }

   @mixin col($num,$name) {
     width: col-calc(#{$num},#{$name});
   }

   @for $num from 1 through 12{
     .l-pc-#{$num}{
       @include col($num,mg-pc);
       @extend .pc-col-style;
     }
   }
   @media screen and (max-width: MED(f1)){//Tabletスタイル
     .tb-col-style{
       margin: gMap-col(mg-sp);
       padding: gMap-col(pd-sp);
       box-sizing: border-box;
     }
     @for $num from 1 through 12{
       .l-tb-#{$num}{
         @include col($num,mg-sp);
         @extend .tb-col-style;
       }
     }
   }
   @media screen and (max-width: MED(f3)){//SPスタイル
     .sp-col-style{
       margin: gMap-col(mg-sp);
       padding: gMap-col(pd-sp);
       box-sizing: border-box;
     }
     @for $num from 1 through 12{
       .l-sp-#{$num}{
         @include col($num,mg-sp);
         @extend .sp-col-style;
       }
     }
   }

   .l-row{
     display: flex;
     flex-wrap: wrap;
     @include media(MED(f3)){
       // margin: gMap-col(row-pc);
     };
    .l-row{
     margin: gMap-col(row-pc);
    }
   }

   .l-container{
     padding:{
       top: 75px;
       right: 6%;
       bottom: 80px;
       left: 6%;
     }
     margin: auto;
     @include media(MED(f3)){
     }
   }



//<=========== grid_system end ===========>

おわりに

お世話になった記事