CSSでもオブジェクト指向を実現する書き方

英語版は[こちら](https://github.com/BYODKM/Objective.css)。

> OOCSSとは異なり、CSSでちゃんとオブジェクト指向を実現するための方法について解説します。

## 0. まず「オブジェクト指向」とは

「オブジェクト指向」はIT業界を支えている重要なパラダイムのひとつで、JavaScriptを含む様々なプログラミング言語でサポートされています。特徴としては「型」や「クラス」といった雛形を持ち、雛形から生成された「インスタンス」とクラスとを区別します。

クラスとインスタンスとを区別することで、長期的にメンテナンスしやすいプログラムにすることができます。クラスを修正したり、インスタンスに変更を加えたり、それぞれ自由に拡張できます。

こういったオブジェクト指向プログラム言語（OOPL）に共通の特徴は、CSSでは見られることがありませんでした。2008年にOOCSSという手法が登場した後もです。

それも今日でお終いです。さっそく見ていきましょう。

## 1. 親クラスは先頭大文字で

```sass:Sass__or__Stylus
.Button
  appearance: none
  position: relative
  display: inline-block
  box-sizing: border-box
  border: 1px solid
  border-radius: 4px
  height: 2em
  padding: 0 0.75em
  color: inherit
  background-color: white
  text-decoration: none
  line-height: 1.9
  vertical-align: middle
```

ちょっと馴染みのない書き方ですが、他の言語では一般的なやり方です。

```js:JavaScript
var button = new Button();
```

こうすることで、親クラスとインスタンスとを見分けることができるようになりました。

## 2. インスタンス化はハイフンふたつで

インスタンス化はこのようにします。

```html
<button class="Button button--upload" type="button">アップロード</button>

<a href="#" class="Button button--cancel">キャンセル</a>
```

## 3. インスタンスのプロパティを追加する

```sass
.button--upload
  color: white
  border-color: transparent
  background-color: $green

.button--cancel
  color: white
  border-color: transparent
  background-color: $red
```

親クラス側で念入りに書いてあるお陰で、インスタンスのプロパティはすっきり・短く書けます。

## 4. インスタンスは独自の子要素を持てる

```html
<button class="Button button--upload" type="button">
  <span class="button--upload__icon"></span>
  <span class="button--upload__counter">1</span>
  アップロード
</button>
```

```sass
.button--upload
  color: white
  border-color: transparent
  background-color: $green

  & &__icon
    @include icon(upload)

  & &__counter
    position: absolute
    top: -0.75rem
    right: -0.75rem
    padding: 0.1em
    min-width: 1em
    height: 1em
    border-radius: 0.5em
    overflow: hidden
    font-size: 0.75em
    line-height: 1
    background-color: $red
```

`& &__` は打ち間違いではありません。安全なスコープを作り出しています。

ここで覚えておくべきなのは、ここにある子要素はインスタンスのものであって、親クラスのものではないということです。つまり、これらは継承されません。

## 5. BEMとの違い

- `--` や `__` といった、セパレーターが持つ意味合いは同じです
- ただし、孫要素があっても `.block__element__element` というふうにはなりません
- 子孫要素はそれぞれ識別できる名前であれば十分です
- フォーマットとしては `.type--identifier__element` になります

## 6. OOCSSとの違い

OOCSSはOOPLが持つ主要なコンセプトを実現していません。

- カプセル化
- 継承
- メッセージング

OOCSSの「OO」は[比喩](https://github.com/stubbornella/oocss/wiki/FAQ)だそうです。

## 7. 親クラスが子要素を持つ場合の例

```html
<div class="Popup">
  <div class="Popup__window">
    <div class="Popup__message">
      <!-- メッセージをここに -->
    </div>
    <div class="Popup__action">
      <!-- ボタンをここに -->
    </div>
  </div>
</div >
```

これらの子要素は親クラスの構造の一部なので、将来のマークアップで継承されます。

### 7.1 親クラスのプロパティ

```sass
.Popup

  & &__window
    width: 300px
    position: fixed
    top: 33%
    left: 50%
    margin-left: -150px
    border-radius: 8px
    background-color: white

  & &__message
    padding: 1rem

  & &__action
    padding: 0.5rem
    border-top: 1px solid $gray
    text-align: center
```

### 7.2 インスタンス化

```html
<div class="Popup popup--confirm">
  <div class="Popup__window">
    <div class="Popup__message">
      <p class="popup--confirm__message">メッセージを送信しました。</p>
    </div>
    <div class="Popup__action">
      <button class="Button button--close-popup" type="button">閉じる</button>
    </div>
  </div>
</div >
```

### 7.3 インスタンスのプロパティ

```sass
.popup--confirm

  & &__message
    text-align: center
```

ここまでは `.Button` の例と同様です。

## 8. 親クラスの子要素を上書きしたい場合は？

### 8.1 不正解例

以下のやり方はよくありません。

```html
<div class="Popup popup--confirm">
  <div class="Popup__window">
    <div class="Popup__message">
      <p class="popup--confirm__message">メッセージを送信しました。</p>
    </div>
    <div class="Popup__action">
      <!-- 今回は閉じるボタンなし -->
    </div>
  </div>
</div >
```

```sass
.popup--confirm

  .Popup__action
    display: none
```

上のコードは、インスタンス側から親クラスの子要素を直接操作しています。この方法だと親クラスの内部構造に変更があった場合、インスタンスにも影響が出ている可能性があり、目視での検証作業を必要とします。やめましょう。

### 8.2 正解例

正しくは、引数を使って対応します。

```html
<div class="Popup popup--confirm param--auto-close"><!-- ここに引数を追加 -->
  <div class="Popup__window">
    <div class="Popup__message">
      <p class="popup--confirm__message">メッセージを送信しました。</p>
    </div>
    <div class="Popup__action">
      <!-- 今回は閉じるボタンなし -->
    </div>
  </div>
</div >
```

```sass
.Popup

  &.param--auto-close

    .Popup__action
      display: none
```

このコードなら、親クラスが自分の子要素をハンドリングしているだけなのでとても安全です。インスタンスは親クラスの内部構造について何も知る必要がありません。

以上で、オブジェクト指向なCSSが出来上がりました。以下のチェックリストもチェックしておきましょう。

- カプセル化 ✔︎
- 継承 ✔︎
- メッセージング ✔︎

## 9. 謝辞

最後までお読みいただき、ありがとうございました。

気に入っていただけると幸いです。