学習し、自分なりに噛み砕いて、書き出すブログ。

神獄のヴァルハラゲートの CSS 設計

CSS Architecture Advent Calendar 2014 9 日目の記事になります。

神獄のヴァルハラゲートの CSS 設計方法について振り返りつつ、こうしているということや、上手くいったところ、改善したいところを書いていこうと思います。

アプリの規模

ASP.NET MVC を使っていて、View 側は Razor テンプレートを使っているのですが、Razor のファイルを検索してみると以下の量となります。

find ./ -name "*.cshtml" | wc -l
    1674

実際には、これにフィーチャーフォン向けのファイルや、部分的な View ファイルも含まれています。

なので、実際 CSS を適用しているファイルの量は、この検索結果よりは格段に減りますが、それでも、約 600 ファイルはあると思います。

ちなみに、今年のはじめに同僚の@mayukiが、ソーシャルゲームのフロントエンドと ASP.NET MVC (Lite)というタイトルで、めとべや東京#3 (Room metro Tokyo #3)にて発表したのですが、そこには「View 数は 400 超」と書いてあるので、1 年間の運用で約 200 ファイル増えたことになります。

対応端末、ブラウザー

スマートフォンでは、以下の環境でアクセスされることを想定して対応しています。

OS

  • iOS 6 or later
  • Android 2.3.x
    • 重要な機能だったら、Android 2.2.x にも対応することも…
  • Android 4.0 or later

ブラウザー

  • iOS
    • Safari
    • WebView
  • Android

iOS 6 や Android 2 系はそろそろ対応端末から外したいなと思っています。来年の今頃は対応しなくて良くなってたらいいですね。

命名規則

BEMを採用しています。ただし、セレクタの命名規則は以下のように変えています。

[prefix]-[block]_[element]-[[Modifier-Key]-[Modifiler-Value]] {
  // property: value;
}

今年のネーミングルール #CSS 設計 - < /gecko >とだいたい同じですが、以下の点が異なります。

  • Block と Element の区切り文字は「_(アンダースコア)」
  • 複数の単語を連結する場合は「-(ハイフン)」を使う
  • Modifier は CamelCase を使う。例は以下の通り
    • foo-Bar-Baz ([block]-[Modifier-Key]-[Modifier-Value])
    • foobar-Baz ([block][element]-[Modifier-Value])
  • prefix は、共通で使うルールセットはプロジェクトのコードネーム、各機能のみで使うルールセットはその機能名を使う
    • ガチャなら prefix はgachaという感じ

あとは、hiloki/flocssの MindBEMding の章にあるように、JavaScript で操作されるような「状態」を表すような Modifier については、SMACSS の State パターンの命名のように、is-*プレフィックスを付けて.is-activeという感じにしています。

.is-activeには直接スタイル指定をすることを禁止しています。

// これはOK
.block_element.is-active {
  display: block;
}

// これはNG
.is-active {
  display: block;
}

良いところ

  • --__という区切り文字より、セレクタ名が醜くならない(個人の主観です)

あとは構造が分かりやすいだったり、class 名が衝突するということが少ないという、BEM や MindBEMding を採用した人ならだいたい感じることでしょうか。

改善したいところ

  • prefix のところで世代管理をしなかったのは間違いだった
  • Modifier を使っている class 名で、Modifier-Key がない class 名というのは、分かりにくいのではと思った
    • この章を書いて気づいた…

ディレクトリ構成

hiloki/flocss に基本は準拠しています。「基本は」と書いたのは以下のディレクトリ名を自分の好みで変えているからです。

  • foundation -> base
  • object/project -> object/page

使っている CSS プリプロセッサーやライブラリー

  • LESS
  • Normalize.css

LESS な理由ですが、ソーシャルゲームのフロントエンドと ASP.NET MVC (Lite)の 7 ページにも書いてあるように、Visual Studio との相性が良かった(新規ファイル作成時に*.less 形式でのみファイルが作れた)ことが要因です。

とはいえ、MSDN Blogs のAnnouncing new Web Features in Visual Studio 2013 Update 2 CTP2にも書かれているように、Visual Studio 2013 Update 2(ちなみに今は Update 4 が最新)から公式に Sass(*.scss 形式)のファイルも新規作成できるようになったので、Visual Studio ユーザーでも好みで LESS か Sass かを選べるようになったと言えます。

ライブラリーは Normalize.css くらいしか使っていないです。これはやはり同僚の@mayuki が入社したての頃に、汎用 class をゴリッと書いてくれたので、ライブラリーを使う理由があまり無くなったという感じです。

CSS プリプロセッサーの機能について

extend

CSS プリプロセッサの Extend - hiloki/flocssに書かれているように、モジュールで完結する extend は許容し、それ以外は禁止しています。むやみに extend を多用すると、どこにそのルールセットが書かれているか分からなくなり破綻する、というのが大きな理由です。

ルールセットの入れ子

CSS プリプロセッサーのほとんど(全て?)はルールセットの入れ子がおこなえますが、入れ子の深さは二段階までと定めています。具体例としては以下のコードです。

.foo {
    border: 1px solid #003760;
    color: #000;
    background: rgba(0, 0, 0, 0.5);

    .nest-01 {
        font-weight: bold;

        .nest-02 {
            color: #f00;
        }
    }
}

なぜ、二段階までに抑えているのかというと、制限がなかった場合、出力後の CSS のセレクタ部分がとても長くなってしまう可能性があるということが挙げられます。

具体例を書くと、以下のような LESS のコードがあったとします。

// Uuuugly!
.foo {
    .nest-01 {
        .nest-02 {
            .nest-03 {
                .nest-04 {
                    .nest-05 {
                        color: #333;
                    }
                }
            }
        }
    }
}

上記のコードを CSS にコンパイルした場合、以下のようになるでしょう。非常に長くて醜いです。

.foo .nest-01 .nest-02 .nest-03 .nest-04 .nest-05 {
  color: #333;
}

また、実際に挙動を確かめられていないですが、多くのサイトで「ブラウザーのセレクターの解釈として、右から左に解釈される」と書かれています。

とすると、上記の CSS は「.nest-05 -> .nest-04 -> .nest-03 -> .nest-02 -> .nest-01 -> .foo」と解釈されることになります。「.nest-01 -> .foo」という構造よりも解釈に時間がかかりそうです。

ちなみに、古い記事(2011 年)ですが、CSS セレクタによる高速化、実際のところ « LINE Engineers' Blogに実際の計測結果が掲載されており、そこには以下のように書かれています。

・スタイルを当てる要素にはできるだけclass又はIDを指定する
・子孫セレクタは重いのできるだけ減らす
という施策に一定の効果はあるようですが、その効果が如実に現れるのはHTML、CSSのコードが非常に大きいページに限られるようです。
そのなかでも、子孫セレクタを減らす施策よりも、スタイルを当てる要素にはできるだけclass名を指定する施策のほうが、効果があるようです。

ということで、MindBEMding の考え方を適用し、ある Block の中でスタイルを当てたい要素には、.block_element だったり、.block_element-Key-Value という感じで class 名を指定し、スタイルを適用しています。

まとめ

ソーシャルゲームというのは、最初から機能が数十種類あったり、View のファイル数が数百ファイルを超えるということは珍しくないと思います。

そんな中で、CSS を書く上での指針がないと、時間が経つにつれ運用が苦痛になってきます。

例えば新しい人が入ってきたり、自分に何かあって他の人が一時的にプロジェクトに入ってきた場合、CSS を書く上での指針が無いと、どのように CSS を書いていけばいいのか、理解に時間がかかることになります。

なので、CSS を書く上での指針を定め、かつ、それを GitHub の Wiki など、プロジェクトのメンバーが目に入る場所に残しておくのが重要と、自分は考えています。

明日は、越智さんです。

記事内で紹介した GitHub のリポジトリや記事