💭

SCSSでオレオレutilityを量産する方法(tailwindやbootstrapを導入できぬ場合にちょっとutilityほしいときなど)

2023/02/16に公開

目指すもの

.top-10{
  top:10%;
}
.top-20{
  top:20%;
}
.top-30{
  top:30%;
}

↑こういうのをチマチマ手書きせずに量産する
先に断っておきますが、こんなオレオレutilityが好き勝手なルールで世の中に蔓延り始めたら間違いなく自分は「tailswindとか使ってもろえる?」みたいな感情を持つので、SCSSってこんな使い方できるんだ〜程度に流してもらえると幸いです。
「utilityフレームワーク入れたいけど諸々の事情で入れれない、けどutility使いて〜〜〜〜」みたいな時には役に立つかもしれません

作り方

メディアクエリの準備

desktopのときは〜タブレットのときは〜モバイルのときは〜でutilityをそれぞれ作れるように、判別用のメディアクエリ情報を用意しておきます

$breakpointS: 768px;
$breakpointM: 1025px;

$bpClass: (
  "sp": "(max-width: #{$breakpointS - 1})",
  "tb": "(min-width: #{$breakpointS}) and (max-width: #{$breakpointM - 1})",
) !default;

上記で作ったメディアクエリ情報を元にSCSSを生成するためのmixinを準備します

@mixin mqAll($class, $bp: $bpClass) {
  .#{$class} {
    @content;
  }
  @each $suffix, $value in $bp {
    @media #{$value} {
      .#{$suffix}-#{$class} {
        @content;
      }
    }
  }
}

これでどうなったかというと、

.top-10{
  top:10%;
}
@media (min-width: 768px) and (max-width: 1024px) {
 .tb-top10{
   top:10%;
 }
}
@media (max-width: 767px) {
 .sp-top10{
   top:10%;
 }
}

こんな感じでメディアクエリ毎のスタイルが生まれるようになりました、なっているはず

utilityクラスを出力させてみる

上記のmixinを使って
$property: プロパティ;
$min: ここから;
$max: ここまで;
$step: 何刻みで(1なら1ずつ、0.1なら0.1ずつを100回繰り返す);
$units: 100%と100vwを分けたりするためにつける修飾子;

@include mqAll("w") {
  $property: width;
  $min: 1;
  $max: 100;
  $step: 1;
  $units: p;
  @each $unit in $units {
    @for $i from $min through $max {
      $modifier: calc($step * $i);
      $prefix: if($modifier > 1, $modifier, $i);
      &-#{$prefix}#{$unit} {
        #{$property}: percentage(calc($modifier/100));
      }
    }
  }
}

ここまですると、

w-1p{
  width:1%
}
w-2p{
  width:2%
}
w-3p{
  width:3%
}
...

上記のようにCSSが出力されたのではないかと思います。されてなかったら私が何か書き漏れてるのでこっそり教えてください

「1~100まで」とかではないパターン

例えばcolorとかは数字で連番を出しても仕方がないので配列を作っておきます

$colorList: (
  primary: #f29d20,
  secondary: #fcf8ed,
  accent: #63a99a,
  caution: #f23420,
  wt: #fff,
  bk: #2b2b2b,
);

↑こんな感じで
ループで呼び出します

@each $key, $color in $colorList {
  .color-#{$key} {
    color: $color;
  }
}

すると

.color-primary{
  color:#f29d20;
}

みたいに出てくるかと思われます。
デザイン上、規則的に配置された美しい余白なども余白配列にいれておけばmarginとかpaddingの管理が楽になります

$spacesList: (
  xs: 10px,
  s: 20px,
  sm: 30px,
  m: 40px,
  ml: 60px,
  l: 80px,
  xl: 100px,
);

適当に10の倍数で刻みましたが、キーと値は各デザイン毎に設定する事になると思います(4の倍数縛りなどあると思うので)
上記配列からmarginのutilityを量産してみます

@include mqAll("mt") {
  @each $key, $space in $spacesList {
    &-#{$key} {
      margin-top: $space;
    }
  }
}

以下のようなCSSが生まれているはず

.mt-xs{
  margin-top:10px;
}
.mt-s{
  margin-top:20px;
}

数値でもないし配列に入れる手間も取りたくないからサッと値別のutility出したい

例えばflexのalign-itemsを例に挙げてみると、

@include mqAll("ai") {
  $property: align-items;
  $values: (
    fs: flex-start,
    c: center,
    fe: flex-end,
    s: stretch,
  );
  @each $key, $value in $values {
    &-#{$key} {
      #{$property}: $value;
    }
  }
}

こんな感じで

.ai-c{
 align-items:center;
}
@media (min-width: 768px) and (max-width: 1024px) {
 .tb-ai-c{
  align-items:center;
 }
}
@media (max-width: 767px) {
 .sp-ai-c{
  align-items:center;
 }
}

あるプロパティの指定した値のutilityが量産される、みたいなことになります

これらのコネコネを好きにコネコネすると、HTMLにclassを振るだけで大概のデザインは再現できるようになります。私のような、

  • デザインFIXしたと言われた後に仕様が変わりまくって跡形もない、その度にSCSS改修してられん
  • 「そもそもワイヤーやんこれ」みたいな段階でコーディングを要求される
  • 上記に加え、CSSフレームワークを導入できない事情がある
    みたいなケースでは心強い味方になることもありますが、これが心強いのは【0⇨1】の時だけです。これらの保守しなければならない方々はきっと私を恨み、憎み、デスノートに名前を書くことでしょう。

SCSS一切触らずにボタンを作ってみる

HTML

<a class="w-30p d-b ml-a mr-a mt-sm mb-sm bg-wt fw-b fz-ml ls-1 ta-c color-primary hov-color-wt hov-bg-primary bd-w-2 bd-rd-20 bd-c-primary ts-4 ts-d-2 crs-p">ボタン</a>

適用されているクラス

width:30%;
display:block;
margin-left:auto;
margin-right:auto;
margin-top:20px;
margin-bottom:20px;
background-color:#fff;
font-weight:bold;
font-size:28px;
letter-spacing:0.1em;
text-align:center;
color:#f29d20;
background-color:#fff;
cursor:pointer;
border-style:solid;
border-width:2px;
border-radius:20px;
transition:0.4s;
transition-delay:0.2s;
:hover{
color:#fff;
background-color:#f29d20;
}

出来上がったモノ

Fooooooo!!SCSS(CSS)を開かなくてもHTMLだけでアニメーション付きのボタンが作れましたね!
繰り返しますが、これが心強いのは【特殊なケースの0⇨1】の時だけです。bootstrapやtailwindなどを導入できる場合はそちらを利用しましょう。フレームワークのメリットは、「readmeを読まなくても作業者が大体使い方を把握できる」というところにあります

Discussion