ラボ > CSS:Sass

sass 似たようなclassをループで作成(each、if、map-get)

配列で回して似たようなclassをまとめて作成する

作成日:2022-09-01, 更新日:2022-12-23

基本

細かいことはよく分からない・・・とりあえずやりたいことは似たような処理を一括で作成したい

今回やりたいことはbootstrapの「btn-xxx」の一部の設定を任意の値に書き換えたい。

一括で置き換えたい

配列みたいなヤツを作成する

シンプルなヤツ

// 配列を作成
$xxx: (
  name01: #ff0000,
  name02: #ffff00,
  name03: #ffffff
);

// ループで回す
@each $key, $value in $xxx {
  .btn-#{$key} {
    color: $value;
  }
}

// ▼こんなCSSが出来上がる
// .btn-name01 { color: #ff0000; }
// .btn-name02 { color: #ffff00; }
// .btn-name03 { color: #ffffff; }

複雑なヤツ(※連想配列)

// 配列を作成
$xxx: (
  group01: (
    col: #ff0000,
    bgcol: #00ffff,
  ),
  group02: (
    col: #ffff00,
    bgcol: #0000ff,
  ),
  group03: (
    col: #ffffff,
    bgcol: #000000,
  ),
);

// ループで回す
@each $grp, $row in $xxx {
  .btn-#{$grp} {
    color: map-get($row, col);
    background-color: map-get($row, bgcol);
  }
}

// ▼こんなCSSが出来上がる
// .btn-group01 { color: #ff0000; background-color: #00ffff; }
// .btn-group02 { color: #ffff00; background-color: #0000ff; }
// .btn-group03 { color: #ffffff; background-color: #000000; }

条件分岐

▼こんな感じのif文

@if xxx != "" { // 値がないとき
  color: #ff0000;
}
@else if xxx == hoge { // 値が「hoge」のとき
  color: #00ff00;
}
@else { // その他
  color: #0000ff;
}

サンプル

今回はbootstrapの「btn-xxx」を一部を書き換える(※主にhoverの背景色を指定したい)
※予めbootstrap.cssを読み込んだ上で上書きする

ループで回す元データ

▼使わない項目も将来的に使うかもしれないのでひとまず記載し、コメントにしておく

$overwrite-colors: (
  primary: (
    // col: #FFFFFF,
    // background-col: $primary,
    // border-col: $primary,
    // hover-col: #FFFFFF,
    hover-background-col: #F0F8F8,
    // hover-border-col: $primary
  ),
  secondary: (
    // col: #FFFFFF,
    // background-col: $secondary,
    // border-col: $secondary,
    // hover-col: #FFFFFF,
    hover-background-col: #4D7775,
    // hover-border-col: $secondary
  )
);

classを作成

▼コメントされていないものだけ上書きするためにif文を使う

@each $color, $property in $overwrite-btn {
  .btn-#{$color} {
    @if map-get($property, color) != "" {
      color: map-get($property, color);
    }
    @if map-get($property, background-col) != "" {
      background-color: map-get($property, background-col);
    }
    @if map-get($property, border-color) != "" {
      border-color: map-get($property, border-col);
    }

    &:hover {
      @if map-get($property, hover-col) != "" {
        color: map-get($property, hover-col);
      }
      @if map-get($property, hover-background-col) != "" {
        background-color: map-get($property, hover-background-col);
      }
      @if map-get($property, hover-border-col) != "" {
        border-color: map-get($property, hover-border-col);
      }
    }
  }
}

if文が多くて・・・鬱陶しい。もう少し見やすくしたい・・・

多重配列で回してみる

基本、決め打ちなので多重配列にして回す。
見づらく、後日修正するのは面倒な気がする。・・・慣れると見やすいのかな?

$overwrite-btn2: (
  primary: (
    root: (
      color: #FFFFFF,
      background-color: $primary,
      border-color: $primary,
    ),
    hover: (
      color: #FFFFFF,
      background-color: #F0F8F8,
      border-color: $primary
    ),
  ),
  info: (
    root: (
      color: #ff0000,
      background-color: $info,
      border-color: $info,
    ),
    hover: (
      color: #0000ff,
      background-color: #277C89,
      border-color: $info
    ),
  ),
);

@each $color, $grp-css in $overwrite-btn2 {
  .btn-#{$color} {
    @each $property, $value in map-get($grp-css, root) {
      #{$property}: $value;
    }

    &:hover {
      @each $property, $value in map-get($grp-css, hover) {
        #{$property}: $value;
      }
    }
  }
}

「:hover」等も式で出力させる場合

・・・見づらいからコレはしないほうが良さげ。
でも、cssの内容によっては良い感じになりそうな気もする

@each $color, $grp-setting in $overwrite-btn2 {
  .btn-#{$color} {
    @each $key-parent, $row-setting in $grp-setting {
      @if $key-parent == root {
        @each $property, $value in $row-setting {
          #{$property}: $value;
        }
      }
      @else if $key-parent == hover {
        &:#{$key-parent} {
          @each $property, $value in $row-setting {
            #{$property}: $value;
          }
        }
      }
      @else {
        // なにもしない
      }
    }
  }
}

最終形: 見やすさ・項目の増減等を考慮

上書きしたい項目だけ追加すればOKなようにしてみた
・・・ココまでするなら別の方法を考慮したほうが良いような気もする

サンプル

後日、復活させる or 知らない人が修正するときに分かるように使わない項目をコメントしておく

$overwrite-btn2: (
  primary: (
    //root: (
    //  color: #FFFFFF,
    //  background-color: $primary,
    //  border-color: $primary,
    //),
    hover: (
      color: #FFFFFF,
      background-color: #F0F8F8,
      border-color: $primary
    ),
  ),
  info: (
    root: (
      color: #ff0000,
      // background-color: $info,
      border-color: $info,
    ),
    // hover: (
    //   color: #0000ff,
    //   background-color: #277C89,
    //   border-color: $info
    // ),
  ),
);

@each $color, $grp-setting in $overwrite-btn2 {
  .btn-#{$color} {
    @if map-get($grp-setting, root) != "" { // 「root」があるときだけループ処理
      @each $property, $value in map-get($grp-setting, root) {
        #{$property}: $value;
      }
    }

    @if map-get($grp-setting, hover) != "" { // 「hover」があるときだけ「&:hover{}」を追加して、その中でループ処理
      &:hover {
        @each $property, $value in map-get($grp-setting, hover) {
          #{$property}: $value;
        }
      }
    }
  }
}

サンプル2: コメントを削除したバージョン

ある程度、記述になれたら余計なコメントを削除。

$overwrite-btn2: (
  primary: (
    hover: (
      color: #FFFFFF,
      background-color: #F0F8F8,
      border-color: $primary
    ),
  ),
  info: (
    root: (
      color: #ff0000,
      border-color: $info,
    ),
  ),
);

@each $color, $grp-setting in $overwrite-btn2 {
  .btn-#{$color} {
    @if map-get($grp-setting, root) != "" {
      @each $property, $value in map-get($grp-setting, root) {
        #{$property}: $value;
      }
    }

    @if map-get($grp-setting, hover) != "" {
      &:hover {
        @each $property, $value in map-get($grp-setting, hover) {
          #{$property}: $value;
        }
      }
    }
  }
}