1-4no diary

自作キーボード, CSS, その他好きなことなど

CSS設計でボタンのコンポーネント対応って実は難しいのでは?と思ったらそもそもに問題があるかも

CSS設計やコンポーネント化を考える上で、ボタンというのはよく例にあげられます。
しかし、パターンが多いと、コンポーネント化がとても難しいです。

ボタンのパターン

ボタンのよくあるパターンを考えてみます。
(ここからはBEMを使用していることを前提に進めていきます)

色違い

これは特に問題ありません。
下記の用になるかと思います。
hover 処理を mixin にしています。

.btn {
  // 共通ルールは省略

  @mixin set_btn_color($background_color, $amount: 7) {
    background-color: $background-color;
    transition-duration: 0.3s;

    &:hover {
      transition-duration: 0.3s;
      background-color: darken($background-color, $amount);
    }
  }

  &--primary {
    @include set_btn_color(#f00);
  }
  &--secondary {
    @include set_btn_color(#0f0);
  }
}

サイズ違い

問題となるのはここです。
サイズを指定する方法が複数存在しているためです。
それぞれの方法について確認していきます。

width, height が固定されている

一番シンプルなパターンです。
完全にサイズが固定化されているというものです。
small, medium, large くらいのパターンで終わるのあればいいのですが、
クラス名にサイズが入ってくるようになればそれはちょっと設計的に失敗したといえるでしょう。
また、テキストが長くなるとボタンの中に収まらなくなることもあるので、汎用性はないといえます。

.btn {
  // 共通ルールは省略

  &--small {
    width: 〇〇px;
    height: 〇〇px;
  }
  &--medium {
    width: 〇〇px;
    height: 〇〇px;
  }
  &--large {
    width: 〇〇px;
    height: 〇〇px;
  }

  // ここからははやりすぎ
  &--w300h80 {
    width: 300px;
    height: 80px;
  }
  &--w300h100 {
    width: 300px;
    height: 100px;
  }
}
padding, min-width, min-height を指定

これはよくあるのではないでしょうか?
サイズ固定と違い中の文言によってサイズが変わっていきます。
そのため、テキストが収まらないということはなくなりますが、サイズを完全に統一することはできなくなります。

.btn {
  // 共通ルールは省略

  &--small {
    min-width: 〇〇px;
    min-height: 〇〇px;
    padding: 〇〇px;
  }
  &--medium {
    min-width: 〇〇px;
    min-height: 〇〇px;
    padding: 〇〇px;
  }
  &--large {
    min-width: 〇〇px;
    min-height: 〇〇px;
    padding: 〇〇px;
  }
}
指定なし

ボタン自体にはサイズを持たせないというパターンです。
ボタンコンポーネントを使用する場合は、ボタンを入れる要素(親要素)でサイズを指定したり、別途クラスを付与(マルチクラス)で対応する必要があります。
汎用性はとてもありますが、単体ではサイズの指定ができないので、サイズという Modifier を持っていないだけともいえます。

.btn {
  // 共通ルールは省略

  width: 100%;
  height: 100%;
}

displayには何を指定するか?

これも悩みます。
中に入る文字列を中央寄せにしようとすると、inline-block, flex あたりにしたくなります。
1行限定であれば、block でも line-height = height にすれば可能ですが…。

ボタンのコンポーネントって難しくない?

見出しや、カード的なコンポーネント作成する方がよっぽど楽じゃん…。

と思いました。

デザインを確認しても、このサイズ指定が入り乱れていることもあると思います。

「このボタンはテキスト折り返しているのでサイズ固定?」
「このボタンは2文字だけど結構大きめだからサイズ固定?」
「このボタンはテキストによってサイズ変わっていそうだから padding で実装する?」

というように、わけがわからなくなります。

「padding実装で可変でお願いね」と言われてもそこから、最小サイズやパターンを見つけるのは結構大変です。

全ての要望を満たすボタンを作る

結局、可変も固定も混在していることが判明したとします。

それを受けて、下記のようなことを考えながらボタンクラスを作ってみるとします。

  • サイズは、固定、可変に対応できるようにそれぞれのクラスを用意する
  • サイズ + (可変 / 固定)クラスの組み合わせでいい感じになるようする

できました。

.btn {
  $block: &;

  // 共通ルールを記入
  ... 省略

  // サイズの指定
  &--small {
      padding: 3px 5px;
      font-size: 1.2rem;
      border-radius: 3px;

    &#{$block}--fix {
      min-width: 60px;
      min-height: 40px;
    }
    &#{$block}--variable {
      width: 60px;
      height: 40px;
    }

  }
  &--medium {}
  &--large {}

  // 色の指定
  ... 省略
}

こんな感じでしょうか? では、size: small + fix, color: primary のボタンを表示してみましょう。

<button class="btn btn--small btn--fix btn--primary">test</button>

1つのボタンを生成するのに、必要なクラス多くない?

これでも問題ないということであれば、それでもいいと思います。
人によっては、固定ボタンと可変ボタンを別々にしたくなる人もいるのではないでしょうか?
そうすれば、必要なクラスは1つ減ります。(クラス名長くなったので文字数はそんなに変わらず…)
ただ、sassの方は工夫しましょう。
共通部分を重複させると、後々管理が面倒になるので、可能な限り mixin で共通化しましょう。
結局は、クラスを減らすための負荷が sass 側に寄るということです。
とはいえ、関連を切りたいということであれば、共通化しない方がいいです。
一緒に変わるべきか、ということを考えて対応しましょう。

<button class="fixBtn fixBtn--small fixBtn--primary">test</button>

あとは、頻発するパターンは、別名のクラスを用意してしまい、その中で必要なクラスを読み込むこともできます。
ただ、組み合わせパターンから生成したものと、それに気が付かず組み合わせで対応してしまうということも発生してしまします。
そうなると、結局別物ということになってしまうので、使い所が難しい対応方法ではあります。

まとめ

この状態でなにをまとめられるのか…という感じですボタンのコンポーネントって難しくない?というのがまとめです。
結局、パターンが多すぎるということが根本原因だと思います。

サイズに関しては、思い切って決まったパターン以外は管理しないというのもありかなとは思っています。
決まったパターン以外は、その場でサイズ指定をしてもらうという方法です。

基本パターンと例外パターンをわけることでこの対応はできるので、どうしようもないときは試してみてはいかがでしょうか?