<!DOCTYPE LNLY>

白ウサギを追え

BEMの設計とコンポーネント設計の関係の話

同僚との雑談中に BEM の話題に至り、コンポーネント設計の中に現在も活かされている話をしました。

BEM

語られ尽くしたことと思いますが、いわゆる「 CSS 設計」の方法論の一つです。
他にもいくつかの有名な CSS 設計スタイルがありますが、僕は BEM を使う経験が最も多かったです。 この記事では BEM それ自体のやり方は詳しく解説しません。

getbem.com

BEM を端的に言えば、
CSS の仕様に起因するコードの複雑性」を「単一のクラスセレクタに限定すること」によって防ぎ、 「クラス名の衝突」を「クラス名を冗長にすること」によって避けるアプローチ
であると僕は考えています。

今一度考える、BEM がもたらしたもの

BEM の登場は些か前のことになるので、今となっては形式化していることも多いです。
BEM がどんな良いことをもたらしたのか、今一度思い出してみます。

UI のモジュール化

Block は他の Block からのスタイルの影響を受けません。
すでに作成した Block の単位に限っては、レイアウトを自由に変更することができ、 コンポーネントの再利用も簡単にできます。( Block を利用して UI のカタログにすることも!)

ルール

BEM は簡単且つ厳格なルールによって守られているので、個人差による解釈の違いや、例外がなく、学習コストが低いです。
またその運用においても、要素のクラス属性を見れば、コードベースのどの位置にルールが書かれているかを容易にマッピングしやすくなる点が利点です。

コンポーネント設計と BEM

昨今、コンポーネントベースのテンプレートエンジンを組み込んだプロジェクトでは、 BEM がもたらす利点と、クラス名衝突を避けるための方法がエンジンの機能によって代替可能になったことから、 BEM 命名規則を採用する機会は減ってきました。
コンポーネント分割によるモジュール化、また Vue.js であれば <style scoped> にすることでクラス名の一意性はそのコンポーネント内だけの限られた要素さえ考慮すればよくなった、といったことです。

ですが、コンポーネントの設計の考え方自体は BEM による Block の設計となんら変わっていません。

BEM によるモジュール設計

例えば BEM で設計された UI モジュールは次のようになります。

<div class="hoge">
  <p class="hoge__fuga">...</p>
  <p class="hoge__fuga--piyo">...</p>
</div>

CSS または SCSS は、以下のようになります。

.hoge {...}
.hoge__fuga {...}
.hoge__fuga--piyo {...}

SCSS の場合は、以下のようになる場合もよく見られます。

.hoge {
  ...
  &__fuga {
    ...
    &--piyo {...}
  }
}

コンポーネント設計

同じものをコンポーネントベースのテンプレートエンジンで設計するならこうなります。
Vue.js を使った場合を想定しています。
内包されるコンポーネントhoge コンポーネント側に書くことが多いですが、概念としてはこのような感じです。

<hoge>
  <fuga>...</fuga>
  <fuga :piyo="true">...</fuga>
</hoge>

CSS は各コンポーネント<style scoped> で書きますので、class 名を冗長にする必要はありません。

終わり

ギョームにおいては別のシチュエーションが考えられます。
なんらかのサーバサイドテンプレート + BEM による CSS 設計( CSS または Sass などのプリプロセッサ )といった環境から、Vue.js へのリプレースなどです。
サーバサイドテンプレートから Vue.js への分離はするが、CSS だけは Vue コンポーネントに移植する工数がないので、既存の CSS をそのまま読み込んでおく、ということもあるでしょう。
既存のコードベースの状態次第になるプロジェクトの場合はそんなにうまくいかないこともありますが、
それがどのように設計され、どう活かせるのかを見出すためには、歴史的背景(今回の話であれば、BEM)について知見を持っておいて損はないことと思います。

Treee の公開とその後のバージョンアップ

進捗をブログに書いていませんでしたが、 Treee を 2019年5月8日に突然公開しました。

https://treee.app

その後やった以下のことを進捗報告として記事にします。

  • Twitter アカウントの運用を開始
  • Figma によるロゴデザイン
  • エディタ機能の一部アップデート
  • UIデザインのアップデート

Twitter アカウントの運用を開始

個人アカウントとは配信する内容に差をつけたいことからTwitterは専用のアカウントを立ち上げました。
Treee はそのショートカットなど覚える操作が多いことからそれらのTipsの配信や、
バージョンアップ情報などの告知として使えればと考えています。

Figma によるロゴデザイン

f:id:lnly:20190516002342p:plain
TreeeLogoType

ロゴデザインは Figma を使って制作しました。デザインツールの使用経験はもちろんデザイン自体の経験がないため初めての制作になりましたが、
Figma はとても使いやすく思い通りのものができました。

マークは正三角形を敷き詰めて「木」のモチーフを作り、 テーマカラー2色を使って緩やかにグラデーションさせるパターンと、ベタ塗りのパターンを使い分けられるようにしました。
ロゴのフォントは Roboto を使い、ウェイトは Light をベースに小さいサイズの視認性を考慮して太さを若干いじっています。

エディタ機能のリリース後アップデート

リリース時に盛り込まなかったいくつかの機能を追加でリリースしました。

  • 選択したノードを兄弟間で、または世代間で移動できる機能
  • 未保存の変更がある時にウィンドウを閉じようとした場合に警告を表示
  • 一定時間おきに未保存の変更を自動的に保存できる機能

選択したノードを兄弟間で、または世代間で移動できる機能

初めから作りたいと思っていたもの実現方法が思い浮かばなかったため保留としていましたが、
コピー&ペースト機能の副産物で比較的簡単に実現できました。

一瞬で入れ替わってしまうと何が起きたかがわかりにくく感じられたため、
ノードの追加時や削除時に若干のトランジションを追加しました。

未保存の変更がある時にウィンドウを閉じようとした場合に警告を表示

うっかり消してしまうことがユーザーデメリットが大きすぎるため、 デザインは何も作っていませんが(ブラウザ標準の)警告を表示するようにしました。

一定時間おきに未保存の変更を自動的に保存できる機能

実は当初、Undoができないので「勝手に保存されるのも困る」と考えていたため、
Undo機能と同時にリリースする想定でした。
しかしこれも消えた場合のユーザーデメリットの大きさを改めて考慮し、先行で自動保存を実装しました。

現在の設計上の制約によりリアクティブに(変更が生じたら即)保存することが難しく、
なくなくポーリングでの定期保存に落ち着いています。

UIデザインアップデート

f:id:lnly:20190516004025p:plain
Treee一覧画面のUI変更

色付きのボタンや、文字のみのボタンなど、いくつかの基本的なコンポーネントで作られていた UI ですが、デザインをリファインしました。

特に新規追加ボタンはアクションの重要性から他の汎用ボタンよりも大きく、色や形状も変化させています。

進捗は以上です。

簡単ですが今回の報告はこれで以上です。