UnityのUI ToolkitのVisual ElementやUSSのクラスの名前をBEMベースで厳密に命名する方法についてまとめました。
厳密な命名の重要性
USSでは以下の記事のように複雑なセレクタの指定方法を使うことで、柔軟にスタイルを適用できます。
しかしながら柔軟であるがゆえに、複雑すぎるセレクタがあったり、セレクタの分け方のルールが曖昧だったりすると、他人が理解できなくなり、大人数で効率よく開発することが難しくなります。
この問題を解決するために、UnityではBEMベースの命名を推奨しています。
BEMとはWebの文脈から生まれた、CSSにおける拡張性や保守性を保つための命名手法です。
本記事ではUnityにおけるBEMの概念や実際の使い方についてまとめます。
BEMの概念
BEMでは適切な命名を行うために、各UIのパーツをBlock, Element, Modifierという概念で整理します。(これらがBEMの名前の由来です)
まず、ヘッダー、検索フィールド、タブなどの各パーツをBlockと呼びます。
また、Blockの中にあるテキストフィールドやボタンなどの各要素をElementと呼びます。
ここで、検索フィールドが空の時にボタンの見た目が押せない状態に変わるとします。
このような状態を表すための装飾をModifierと呼びます。
ModifierにはBlockに対するものとElementに対するものがあります。
今回の例はボタンElementに対するModifierということになります。
BEMベースの命名規則
BEMでは、前節で説明したBlock, Element, Modifierを組み合わせて、以下のルールに基づいてクラスを命名します。
- Block, Element, Modifierを複数単語で構成する場合には単語間をハイフンで繋ぐ
- BlockとElement間はアンダースコア二つで繋ぐ
- ElementとModifierの間はハイフン二つで繋ぐ
これを前節の検索フィールドの例に照らし合わせると、各クラスの命名は以下の通りとなります。
- 検索フィールド:
search-field
- 検索フィールドのボタン:
search-field__button
- 検索フィールドのボタン(押せない状態):
search-field__button—-disabled
USSの記述としては以下のようなイメージです。
.search-field { flex-direction: row; } .search-field__button { color: #E5E5E5; background-color: #929292; } .search-field__button—-disabled { color: #929292; background-color: #3F3F3F; }
なおこの辺りの命名ルールはBEMとして特定の決まりがあるわけではありません。
本記事ではUnityが推奨している命名方法を紹介しています。
クラスを適用する
次に、前節のクラスを実際に検索フィールドのボタンに適用することを考えます。
クラスを適用するには、スタイルシートを適用した上で、VisualElement.AddToClassList
でデフォルトのスタイルが記述してあるsearch-field__button
クラスを追加します。
var button = searchField.Q<Button>(); // 適切な方法で対象のボタンを取得する button.AddToClassList("search-field__button");
スタイルシートの適用の仕方は割愛しますが、以下の記事にまとめていますので必要に応じて参照してください。
https://light11.hatenadiary.com/entry/2020/03/08/202458#StyleをUSSファイルに切り出す
ボタンが押せない状態になったら、押せない状態の時に上書きするべきスタイル情報が記述してあるsearch-field__button—-disabled
を追加します。
再び押せる状態になったらVisualElement.RemoveFromClassList
でそれを削除します。
button.AddToClassList("search-field__button--disabled"); // クラスを追加 button.RemoveFromClassList("search-field__button--disabled"); // クラスを削除
ちなみにこれらのメソッドの他にVisualElement.EnableInClassList
やVisualElement.ToggleInClassList
がありますが、これらは上述のメソッドの単なるラッパーです。
VisualElementの継承とクラス
次に、UIToolkitのButtonを継承してプロジェクト独自のCustomButton型を作ることを考えます。
このとき、Buttonのコンストラクタではunity-button
クラスが適用されています。
CustomButtonでスタイルをオーバーライドしたい場合には、custom-button
のようなクラスを新しく作り、unity-button
クラスから変更したいスタイルだけを記述し、VisualElement.AddToClassList
で追加します。
つまり、CustomButtonにはunity-button
とcustom-button
の両方のクラスが適用されていることになります。
このように、VisualElementを継承した際には継承した分だけスタイルを記述したクラスを追加していくことになります。
外部ツールなどを作る際の注意点
上述の通りUSSのクラスはそのクラス名を用いて解決されるため、名前が被らないように注意する必要があります。
特に共通パーツや外部ツールを作る際には注意が必要です。
他プロジェクトでも使用するようなUIを作る場合には、unity-button
のunity-
のようにPrefixをつけることを検討するべきです。