😸

いい感じのmixin作りたいけどすごい冗長的になったのでもっとカッコいいのを書き方を考え中

2022/10/06に公開

基本的なspacingはmarginのbottomとrightで管理したいので下記のようなmixinを作りました。

marginのbottomとrightだけ許容する@mixinを作成

$margins: (
  small: 8px,
  medium: 12px,
  large: 50px,
);

@mixin margin($size: medium, $property: bottom) {
  margin-#{$property}: map-get($margins, $size);
}

.section {
  @include margin(large, bottom);
  @include margin(small, right);
}

// コンパイル後
.section {
  margin-bottom: 50px;
  margin-right: 8px;
}

@mixinの仕様

@mixin margin($size: medium, $property: bottom)

$size$propertyにはデフォルトの値を設定しておきます。

Interpolation(インターポレーション)で文字列として扱う

:::note info
Interpolation(インターポレーション)#{$property}
利用することで動的にプロパティを操作できるようにします。

$property = bottom;
コンパイル前:margin-#{$property}
コンパイル後:margin-bottom

:::

@errorで指定以外を弾く設定を追加

追加でmargin-bottommargin-right以外は許容したくないので、
@errorを追加してbottomとright以外を第二引数に入れるとエラーを出すようにする。
これでおかしな使われ方はできない。

@mixin margin($sizes: (), $property) {
  @if $property {
  }
  @else {
  }
  @if ($property != bottom and $property != right) {
    @error "$propertyはbottomかrightのみ";
  }
  @if (length($sizes) == 1) {
    margin-bottom: marginSize($sizes);
  } @else {
    @for $i from 1 through 4 {
      $property: join($property, $sizes);
    }
    @debug $sizes;
    //margin: marginSize(nth($sizes, 1)) marginSize(nth($sizes, 2));
  }
}

条件分の書き方は注意

:::note warn
条件式で&&||は使えないので、andorを利用する
:::

作った@mixinの課題

いい感じにできたと思いきやこれだと問題が発生します。
コンテンツ間のspacingは@include margin($size, $property);記述できる。
ただ、margin: 0 auto;margin: 10px 8px 12pxとか指定したいてなったら記述バラバラでそのうちカオスになるのではないか?

具体例

.section {
  @include margin(large, bottom);
  @include margin(small, right);
}

.section2 {
  margin: 0 auto;
}

.section3 {
  margin: 10px 8px 12px;
}

@mixinが対応できていない範囲は、これまで通り書かないといけません。
同じmarginを指定するのに違う書き方が存在すると後に混乱を招くかもしれない…。
意図的なのか偶発的なのかは判断できないかもしれない…

@mixinを汎用的に拡張を試みてみる

@mixinを拡張することにしたがめっちゃ冗長的に…

@mixin margin($sizes: (), $property: bottom) {
  @if ($property != bottom and $property != right) {
    @error "$propertyはbottomかrightのみ";
  }
  margin-#{$property}: map-get($margins, $size);
}

第一引数を配列にする。

$propertyのデフォルト値をセットしている場合は諸々の判定に第一引数を使います。

@mixin margin($sizes: (), $property: bottom) {
  @if (length($sizes) == 1) {
    margin-#{$property}: map-get($margins, $sizes);
  }
  @else if (length($sizes) == 2) {
    margin: marginSize(nth($sizes, 1)) marginSize(nth($sizes, 2));
  }
  @else if (length($sizes) == 3) {
    margin: marginSize(nth($sizes, 1)) marginSize(nth($sizes, 2) marginSize(nth($sizes, 3));
  }
  @else if (length($sizes) == 4) {
    margin: marginSize(nth($sizes, 1)) marginSize(nth($sizes, 2) marginSize(nth($sizes, 3) marginSize(nth($sizes, 4));
  }
}

nth()を使って配列から取り出す

:::note info
リストの指定した位置の要素を取得する nth(list, $n)
:::

もっといい書き方があるだと思ってますが…
いい記述方法を考えついたら更新します。

Discussion