CSS設計の類はもっとカスタムデータ属性を活用するべきでは

  • 247
    Like
  • 2
    Comment
More than 1 year has passed since last update.

カスタムデータ属性とは

HTML5で定義されたカスタムデータ属性、当然皆さんご存知のことかと思います。
HTMLにプライベートな値を設定できるという仕様です。
data-から始まる属性です。 このように書きます。

html
<div class="hoge" data-type='fuga'>🐳</div>

この値は、次のようにしてjavascriptやcssから触ることができます。

js
// data-typeを持つ要素を取得
var elem = document.querySelector("[data-type]");
// data-typeの中身を取得する

console.log(elem.dataset.type); // fuga
// data-typeを変更する
elem.dataset.type = 'piyo'; // <div data-type='piyo' />に

scss
// data-typeの文字サイズを大きく
.hoge {
  &[data-type] {
    font-size: 2em; // data-typeを持つ要素の文字サイズを大きく
  }
  // data-typeがpiyoなら末尾にヒヨコを追加
  &[data-type='piyo']::after {
    content:"🐤";
  }
}

細かい仕様や利用可能なブラウザーは他の記事を参考にしていただくとして、
この指定方法とても便利だと思いませんか?

カスタムデータ属性を使った書き換え

例えば次のようなコードがあったとします。

html
<div class="block is-hide"> ... </div>
scss
.block {
  display:block;
  &.is-hide {
    display:none;
  }
}

これをデータ属性付きの方法で書き換えると次のようになります。

html
<div class="block" data-is-hide="true"> ... </div>
scss
.block {
  display:block;
  &[data-is-hide="true"] {
    display:none;
  }
}

data属性に書き換えるだけなので変更も容易です。
さらに特に意識しなくてもCSSの名前が衝突することがなくなりますし、classが短くて済みます。

class名の操作をしなくていいので、javascriptで操作する場合も手軽になります。

const BlockElement = document.querySelector(".block");
let isHide = false;
button.addEventListener("click", () => {
  BlockElement.dataset.isHide = isHide = !isHide;
},false);

Reactと組み合わせても便利

Reactのjsxは、基本的にはsrcなどの予約された属性以外のものを利用することができませんが、data属性なら自由に指定することができます。
次のように書けるので、jsxでstyleを直接当てることなく見た目を変更することも可能です。

<div className="block" data-is-hide={this.state.isHide}>
  ...
</div>

わざわざ条件分岐とかつけなくてもいいわけです

// こんなことしなくてもいい
<div className=`block ${this.state.isHide ? 'is-hide': ''}`>
  ...
</div>

data属性がcssで操作できるということは・・・?

こんなこともできると思います。

html

<div class="block" data-weather="cloudy"></div> // ☁︎
<div class="block" data-weather="sunny"></div> // ☀️
<div class="block" data-weather="rainy"></div> // ☂
<div class="block" data-weather="cloudy-sunny"></div> // ☁︎☀️
<div class="block" data-weather="sunny-cloudy"></div> // ☀️☁︎
<div class="block" data-weather="sunny-rainy"></div> // ☀️☂
<div class="block" data-weather="rainy-cloudy"></div> // ☂☁︎
scss
.block {
  $wathers : (
    'cloudy':'☁️',
    'sunny' : '☀️',
    'rainy' : '☂'
  );

  @each $before, $before_icon in $wathers {
    &[data-weather="#{$before}"]::before {
      content: $before_icon;
    }
  }
  @each $before, $before_icon in $wathers {
    @each $after, $after_icon in $wathers {
      &[data-weather="#{$before}-#{$after}"]::after {
        content: $before_icon + $after_icon;
      }
    }
  }
}

これだけ複雑なことをしても、一切classは汚れません。

グリッドシステムも簡単に(?)

12分割のグリッドシステムもdata属性を使えばより簡単に指定することができます。

html
<div class="row">
    <div class="row__col" data-column="1/3">1/3</div>
    <div class="row__col" data-column="1/3">1/3</div>
    <div class="row__col" data-column="1/3">1/3</div>
</div>

<div class="row">
    <div class="row__col" data-column="2/8">2/8</div>
    <div class="row__col" data-column="9/12">9/12</div>
</div>
scss
.row {
  $min-columns : 1;
  $max-columns : 12;
  width: 100%;
  display:flex;
  &__col {
    margin: auto;
    @for $max_columns from $min-columns through $max-columns {
      @for $i from 1 through $max_columns {
        &[data-column="#{$i}/#{$max_columns}"] {
          @if $i != $max_columns {
            width: ($i / $max_columns * 100%);
          }
        }
      }
    }
  }
}

最後に

というわけで状態の指定にカスタムデータ属性を使うともう少し幸せになるのではないかという提言です。