Scss/floccsで自作ユーティリティー margin / padding編

 

u-mt-20やu-pb-30など、marginでは「u-m」、paddingでは「u-p」の接頭辞がついた、margin又はpadding用ユーティリティーを作成します

フォルダ構成やutilityの適用順などはflocssを基準にしています

社内のコーディング共通フォーマットとして少しずつ独自の改良をしてきた設定です

下記もあわせてご覧ください

ゴール

  • media queryのサイズによる階層的な適用が確実にされること
  • オリジナル名称の設定を作成すること
  • ピクセルごとの設定を作成すること

前提

foundation/variable

使用しないbreak pointを入れておくと無駄な設定ができてしまいますので、注意してください

$break-points: (
  all: '',
  lg: 'screen and (max-width: 1024px)',
  md: 'screen and (max-width: 820px)',
) !default;

$margins: (
  base: (80, 78, 76),
  sm: (50, 48, 46),
  lg: (120, 118, 116),
);

foundation/mixin

@use 'sass:map';
@use 'sass:math';

@function Rem($size) {
  @return math.div($size, 10) + rem;
}

@mixin mq($breakpoint: md) {
  @if($breakpoint == 'all') {
    @content;
  } @else {
    @media #{map.get($break_points, $breakpoint)} {
      @content;
    }
  }
}

使用法

左右auto設定

.u-mx-auto

オリジナル名称の設定

.u-{マージン/パディング方向}-{$margins}

ピクセルごとの設定

.u-{マージン/パディング方向}-{数値}
.u-{マージン/パディング方向}-{$break-points}-{数値}

パラメータ

{マージン方向} … m: margin / mt: margin-top / mb: margin-bottom / mr: margin-right / ml: margin-left / my: margin-block / mx: margin-inline

{パディング方向} … p: padding / pt: padding-top / pb: padding-bottom / pr: padding-right / pl: padding-left / py: padding-block / px: padding-inline

{$margins}{$break-points}は、上記前提を参照

使用例

<div class="u-mb-30 u-mb-lg-40 u-mb-md-50">
・・・
</div>

上記では、画面幅により下記のようになります

  • 1025px以上:「u-mb-30」でmargin-bottomが3rem
  • 821~1024px:「u-mb-lg-40」でmargin-bottomが4rem
  • 820px以下:「u-mb-md-50」でmargin-bottomが5rem
<div class="u-mt-sm">
・・・
</div>

上記では、画面幅により下記のようになります

  • 1025px以上:margin-topが8rem
  • 821~1024px:margin-topが7.8rem
  • 820px以下:margin-topが7.6rem
$margins: (
  base: (80, 78, 76),
  sm: (50, 48, 46),
  lg: (120, 118, 116),
);

上記$marginsの配列の名称(キー)とbreak pointごとの設定は、自由に作成できるので、例えば、buttonやblockなどの設定を作成することで、パターンにあわせた設定を作成することができる上、のち変更があれば、それぞれのmarginやpaddingを一気に更新することもできます。

また、これらは、下記すべてに設定を作成していますので、様々なオリジナルの設定が可能となります

$array: (
  mt: 'margin-top',
  mb: 'margin-bottom',
  mr: 'margin-right',
  ml: 'margin-left',
  my: 'margin-block',
  mx: 'margin-inline',
  m: 'margin',
);
$array: (
  pt: 'padding-top',
  pb: 'padding-bottom',
  pr: 'padding-right',
  pl: 'padding-left',
  py: 'padding-block',
  px: 'padding-inline',
  p: 'padding',
);

最終形

上記の前提は、各環境にあわせ別ファイルとして振り分け、下記ファイルで読み込んでください

margin

@use 'sass:map';

// 上記前提が記載されたファイル
@use '../../foundation/variable' as *;
@use '../../foundation/mixin' as *;

$array: (
  mt: 'margin-top',
  mb: 'margin-bottom',
  mr: 'margin-right',
  ml: 'margin-left',
  my: 'margin-block',
  mx: 'margin-inline',
  m: 'margin',
);

@each $key, $property in $array {
  .u-#{$key} {
    @each $breakpoint, $query in $break-points {
      @include mq($breakpoint) {
        
        // オリジナル名称設定
        @each $name, $values in $margins {
          $num: index(map.keys($break-points), $breakpoint);
          &-#{$name} {
            #{$property}: #{Rem(nth($values, $num))} !important;
          }
        }
        
        // ピクセルごとの設定
        @for $i from 0 through 180 {
          @if $breakpoint=='all' {
            @if $i==0 {
              &-#{$i} {
                #{$property}: 0 !important;
              }
            } @else {
              &-#{$i} {
                #{$property}: Rem($i) !important;
              }
            }
          } @else {
            @if $i==0 {
              &-#{$breakpoint}-#{$i} {
                #{$property}: 0 !important;
              }
            } @else {
              &-#{$breakpoint}-#{$i} {
                #{$property}: Rem($i) !important;
              }
            }
          }
        }
      }
    }
  }
}

.u-mx-auto {
  margin-inline: auto !important;
}

padding

@use 'sass:map';

// 上記前提が記載されたファイル
@use '../../foundation/variable' as *;
@use '../../foundation/mixin' as *;

$array: (
  pt: 'padding-top',
  pb: 'padding-bottom',
  pr: 'padding-right',
  pl: 'padding-left',
  py: 'padding-block',
  px: 'padding-inline',
  p: 'padding',
);

@each $key, $property in $array {
  .u-#{$key} {
    @each $breakpoint, $query in $break-points {
      @include mq($breakpoint) {
        
        // オリジナル名称設定
        @each $name, $values in $margins {
          $num: index(map.keys($break-points), $breakpoint);
          &-#{$name} {
            #{$property}: #{Rem(nth($values, $num))} !important;
          }
        }
        
        // ピクセルごとの設定
        @for $i from 0 through 180 {
          @if $breakpoint=='all' {
            @if $i==0 {
              &-#{$i} {
                #{$property}: 0 !important;
              }
            } @else {
              &-#{$i} {
                #{$property}: Rem($i) !important;
              }
            }
          } @else {
            @if $i==0 {
              &-#{$breakpoint}-#{$i} {
                #{$property}: 0 !important;
              }
            } @else {
              &-#{$breakpoint}-#{$i} {
                #{$property}: Rem($i) !important;
              }
            }
          }
        }
      }
    }
  }
}

解説

上記最終系を一つずつ見ていきます

ループ設定

今回のmarginとpaddingは、「m」と「p」の違いくらいでほとんど差異がないので、marginの設定で確認していきます

$array: (
  mt: 'margin-top',
  mb: 'margin-bottom',
  mr: 'margin-right',
  ml: 'margin-left',
  my: 'margin-block',
  mx: 'margin-inline',
  m: 'margin',
);

接頭辞「u-」に続く名称をキーとして、それぞれにcssのプロパティ名を記載した配列となります

@each $key, $property in $array {
  .u-#{$key} {
・・・
  }
}

設定した配列をeach文でループし、一行ずつ設定していきます

#をつかった「文字列補間(String Interpolation)」を使うことで、$arrayのキーで、class名を作成していきます。下記のように展開されるイメージです

.u-mt {
}
.u-mb {
}
・・・
.u-m {
}

次にmedia queryを設定していきます

$break-points: (
  all: '',
  lg: 'screen and (max-width: 1024px)',
  md: 'screen and (max-width: 820px)',
) !default;

foundation/variableに設定している上記配列を前提にeach分で展開していきます

@each $key, $property in $array {
  .u-#{$key} {
    @each $breakpoint, $query in $break-points {
      @include mq($breakpoint) {
・・・
      }
    }
  }
}

最初の$breakpointは「all」となりますが、下記mixinでは、allの場合は、特に処理を行っていませんので、そのまま設定されます

@mixin mq($breakpoint: md) {
  @if($breakpoint == 'all') {
    @content;
  } @else {
    @media #{map.get($break_points, $breakpoint)} {
      @content;
    }
  }
}

上記により下記のように展開されます

.u-mt {
 // all
 // lg
 @media 'screen and (max-width: 1024px)' {
 }
 // md
 @media 'screen and (max-width: 820px)' {
 }
}
・・・
.u-m {
 ・・・
}

ここでのポイントは、「$break-points」を大きいサイズから設定していことです

これにより、画面幅が小さくなるにつれ、後述の設定が生きてくることになります。

オリジナル名称設定

ここまでで、最終的な各cssを記述する準備が整いました。次に配列「$margins」を展開していきます

$margins: (
  base: (80, 78, 76),
  sm: (50, 48, 46),
  lg: (120, 118, 116),
);

$marginsにある各変数のカッコ内の数字は、$break-pointsの数と同じ数設定しています

したがって、ここは、左から「all」「lg」「md」のpxサイズを数値のみで設定しています

@each $key, $property in $array {
  .u-#{$key} {
    @each $breakpoint, $query in $break-points {
      @include mq($breakpoint) {
        @each $name, $values in $margins {
          $num: index(map.keys($break-points), $breakpoint);
          &-#{$name} {
            #{$property}: #{Rem(nth($values, $num))} !important;
          }
        }
      }
    }
  }
}

上記ブロックの真ん中の部分を解説していきます

@each $name, $values in $margins {

$marginsをeach文で展開していますが、ここでは、最初は「$name」に「base」が、「$values」には「(80, 78, 76)」が入ることになります

$num: index(map.keys($break-points), $breakpoint);

map.keysで$break-pointsのkeyだけの配列を作成しています。結果は「all, lg, md」となります

そしてindex関数で、「all, lg, md」の中でall(二つ目のループで最初の$breakpointは「all」)の位置を取得しています。ここでは「1」が$numとして設定されます

&-#{$name} {

「&-#{$name} {」は、$marginsの最初のキーのbaseを使用して「&-base {」となり、結果として「.u-mt-base」が作成されます

#{$property}: #{Rem(nth($values, $num))} !important;

「nth($values, $num)」では、nth関数で、$values、つまり「(80, 78, 76)」のうち、$numの値の順番(最初は「1」)にある値を取得し、Rem関数でremの値に変換しています

結果として「margin-top: 8rem !important;」という記述が作成されます

下記が展開イメージとなります

// all
.u-mt-base {
 margin-top: 8rem !important;
}
// lg
@media 'screen and (max-width: 1024px)' {
 .u-mt-base {
  margin-top: 7.8rem !important;
 }
}
// md
@media 'screen and (max-width: 820px)' {
 .u-mt-base {
  margin-top: 7.6rem !important;
 }
}
・・・
// all
.u-m-base {
 margin: 8rem !important;
}
// lg
@media 'screen and (max-width: 1024px)' {
 .u-m-base {
  margin: 7.8rem !important;
 }
}
// md
@media 'screen and (max-width: 820px)' {
 .u-m-base {
  margin: 7.6rem !important;
 }
}

ピクセルごとの設定

次にピクセル単位の設定を行います

下記のループ部分は、上記と同じです。2番目のブロックについて解説します

@each $key, $property in $array {
  .u-#{$key} {
    @each $breakpoint, $query in $break-points {
      @include mq($breakpoint) {
        @for $i from 0 through 180 {
          @if $breakpoint=='all' {
            @if $i==0 {
              &-#{$i} {
                #{$property}: 0 !important;
              }
            } @else {
              &-#{$i} {
                #{$property}: Rem($i) !important;
              }
            }
          } @else {
            @if $i==0 {
              &-#{$breakpoint}-#{$i} {
                #{$property}: 0 !important;
              }
            } @else {
              &-#{$breakpoint}-#{$i} {
                #{$property}: Rem($i) !important;
              }
            }
          }
        }
      }
    }
  }
}

今回は、0~180の数値で設定しています

@for $i from 0 through 180 {

「@for $i from 0 through 180」が0~180までの数値をループし$iに0から順に数字を代入しています

@if $breakpoint=='all' {

上記同様allの場合の振り分けをしています

@if $i==0 {

$iの値が0の場合の設定を振り分けています

下記が展開イメージです

// all
.u-mt-0 {
 margin-top: 0 !important;
}
// lg
@media 'screen and (max-width: 1024px)' {
 .u-mt-lg-0 {
   margin-top: 0 !important;
 }
}
// md
@media 'screen and (max-width: 820px)' {
 .u-mt-md-0 {
   margin-top:  !important;
 }
}
・・・
// all
.u-m-180 {
 margin: 18rem !important;
}
// lg
@media 'screen and (max-width: 1024px)' {
 .u-m-lg-180 {
   margin: 18rem !important;
 }
}
// md
@media 'screen and (max-width: 820px)' {
 .u-m-md-180 {
   margin: 186rem !important;
 }
}

上記で特殊なのは「0」設定です。全部のマージンを消したい場合には「u-m-0」が使用できます

marginの追加設定

marginのみ下記設定を追加しています

block要素などのセンター寄せなどで利用できます

.u-mx-auto {
  margin-inline: auto !important;
}

まとめ

以上でmarginとpaddingのユーティリティーの完成となります

全設定が吐き出されてしまうと膨大な量になってしまいますが、弊社では、vite+@fullhuman/postcss-purgecssなどを使って、余計なclassは入らないようにしていますので、そういった工夫も必要になるかと思います

コーディングの省力化に貢献できれば幸いです

文責:フライング・ハイ・ワークス代表 松田 治人(まつだ はるひと)
会社では、Laravelを中心としたエンジニアとして働いており、これまでに50本以上のLaravelによるWebアプリケーションの構築や東京でホームページ制作をしています。
エンジニアとして弊社で働きたい方、お仕事のご相談など、お待ちしております。

WEBサイト・ホームページの制作をご検討の方

コーポレートサイト

フライング・ハイ・ワークスの紹介

フライング・ハイ・ワークスは、東京のホームページ制作・Web制作会社・システム開発会社です。東京都及びその近郊(首都圏)を中心として、SEO対策を意識したPC及びスマホのサイトをワンソース(レスポンシブ対応)で制作します。

実績

デザイナーチームは、グラフィックデザインやイラストの制作も得意としており、著作権を意識しない素材の提供が可能です。システム・コーディングチームでは、Laravelなどを使用したスクラッチからのオリジナルシステム開発を始め、WordPressのカスタマイズを得意としております。

また、SEOやランディングページ(LP)、広告向けバナーなどを他社様でやっていた作業の引継ぎでも問題ありません。制作実績は多数ございますので、お客様に合わせたご提案が可能です。

500点以上のフライング・ハイ・ワークスの制作実績ページをご覧ください。

東京のWeb制作会社・ホームページ制作のお問い合わせ、お見積り依頼、相談、質問は
お問い合わせフォームよりお願いいたします

ホームページ制作実績

コーポレートサイトへ