Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What is going on with this article?
@stophobia

SPA向けのCSS設計 - COCSS

Component Oriented CSS

CSSをもっと便利に使うための努力

CSSの歴史は、言うまでもなく長いです。
テーブルレイアウトの時代から使われ、テンプレートエンジンの時代を経て、JSが定着した最近はフレームワークやライブラリーなどにテーマが移っています。

もはやウェブ開発者・ウェブデザイナーと言う概念から、FE・BE、細かい場合はマークアップエンジニアなど、専門的かつ細分化になっています。
CSSも、専門のエンジニアが活躍する場合もあるくらいです。

こういう流れとともに、CSSの構造に関しても様々な工夫が行われてきました。

代表的には下記の例があります。

  1. OOCSS
  2. BEM
  3. SMACSS
  4. FLOCSS
  5. RSCSS

各例の概念と、不便なところだけ軽くチェックします。
経験者の方は、共感するところもあると思います。

既存の設計、これが不便だった

1. OOCSS

コンテナーとコンテンツで分けて、コンテンツはコンテナーから独立している。
基本構造と見た目を分けて考える(再利用性向上)。

作業して不便だと思った点

  • コンテナーとコンテンツの基準が主観的。
  • コンテンツがまたコンテンツを持つ場合の判定が難しい。
  • クラス名が被ることが多い。

2. BEM

Block(基となる要素)、Element(Block内の子要素)、Modifier(変化した状態)に分けられる。

作業して不便だと思った点

  • BlockとElementの区分が主観的。
  • リファクタリングなどでElementがBlockに変わる場合に手間が掛かる。
  • Modifierの選定基準が曖昧。
  • 要素の変化を動作として見なす場合もある。
  • クラス名が長くなる。

3. SMACSS

Base、Layout、Module、State、Themeに役割を分ける。

作業して不便だと思った点

  • プレフィックスなどルールが増える。
  • 階層が増えると、クラス名も長くなる。

4. FLOCSS

Foundation、Layout、Objectで分けます。

作業して不便だと思った点

  • 小規模サイト・サービスでは運用が難しい(パーフォマンスが悪い)。
  • 徹底に守ると、ファイルが多くなる。
  • プレフィックスと__--などを併用して使うので、クラス名も長くなる。

5. RSCSS

Components、Elements、Variant、Layout、Helpersに役割を分ける

作業して不便だと思った点

  • ComponentsのClass名は必ず2単語以上で組み合わせないといけない。
  • Componentsの中にComponentsが入る場合、Elementsの中にElementsが入る場合わかりづらい。
  • リファクタリングなどでElementsがComponentsに変わる場合に対応が難しい。

だったら、改善しよう

ファイル構造はシンプルに

概ね下記の4つに分けられます。

  • setting.css(sass)

リセットCSSの役割と、Sassなどの変数やmixinなどを定義します。

  • style.css(sass)

ヘッダー、フッターなど全領域に渡るパーツで共通的に使うCSSを指定します。

  • font.css(sass)icon.css(sass)svg.css(sass)...

各目的に合わせてicomoonやfont awesomeなど外部から持ってくるCSSです。
普段触らないことと、作業の手間を減らすため、ルール外とします。

  • コンポーネント内

コンポーネント内で限定して使うCSSは、そのコンポーネント内にScopeを限定して使います。

クラス名から始めよう

一番解消したいのは、クラス名の短縮と最適化です。
クラス名が長くなったり重複が発生してしまうと下記の問題がでてきます。

  • CSS設計時に構造が分かりにくくなる。
  • 作業時にパーフォマンスが悪い。
  • JSと連携する際に把握しづらい。
  • HTMLコード上で見つけづらい。

変化に強いかつ単純なルール

作業の大体は、修正や維持補修です。
新規事業の場合も、途中で何回も仕様が変わります。
やり直す度に構造を意識してしまうと、限った時間内に作業ができなくなるので、諦める場合が多いです。
結果、あれでもこれでもない形でリリースされ、下記の3つでの一択になります。

  • いいケース:CSSを整理するため、また時間をかけます。
  • 悪いケース:放置してしまいます。
  • 最悪のケース:「今回これ使ったからダメだった。。。次回はあれ使おう!」になって、救いの手は遠がる限りです。

なので、「シンプルなファイル構造、わかりやすいクラス名、単純なルール」の3つに集中して対案を考えました。

Component Oriented CSS - COCSS

いよいよ本題に入ります。
COCSSと言う概念をご提案します。

・CSS命名規則だけでなく、SPAのコンポーネント構造に合わせた概念です。
・仕様変更やリファクタリングに強いです。
・クラス名が極端的に短くなります。

簡単なVue製SPAアプリの構造を想定しましょう。

<template lang="pug">
  section
    div.search
      routes#from-route
      routes#to-route
      calendar
      div.-number-panel
        span.icon.icon-checkin
        div.-number-selectors
          number-selector.-hotel
          number-selector.-adult
          number-selector.-child
          number-selector.-baby
      hr.transparent
      button.-submit {{ buttonText }}
</template>

航空券、ホテルを検索する基本的な画面です。
出発地・到着地の入力コンポーネントroutes、日程を決めるコンポーネントcalendar、人数を決めるコンポーネントnumber-selector、パラメタやステータスを渡すコンポーネントbuttonで構成されています。

ルールはいたって簡単です。

画面(コンポーネント)の最上位階層のクラス名

  • アルファベット小文字で始まる
  • 1つの単語で構成する(例:.date
  • 2つ以上の単語で構成される場合は-で連結する(例:.date-today

最上位以下の階層のクラス名

  • -から始まる
  • 2つ以上の単語で構成される場合は-で連結する

これで、各コンポーネントの領域がHTMLソースでも分かりやすくなります。
コンテナーやコンテンツなど、主観的な概念を徹底に排除しました。
CSSの設計に終わらず、コードの構造もシンプルに反映できるので連携がしやすいです。
-は、SassなどCSS内部でも良い区切りになります。

構造と独立したパーツのクラス名

  • アルファベット小文字で始まる
  • 1つの単語で構成する(例:.transparent
  • 2つ以上の単語で構成される場合は-で連結する(例:.icon-checkin

単体に使うパーツは、コンポーネントに拘束されないので、独立したクラス名を使います。icomoonやfont awesomeなど外部のアイコンライブラリーを使う時に、他の設計だと、構造に合わせて名前を変えたりしないといけないですが、COCSSだとそのまま実装できるので、手軽に適用できます。

ID名

  • アルファベット小文字で始まる
  • 2つ以上の単語で構成される場合は-で連結する

IDは、CSSで拘束しないことを原則にしているので厳しい規則は決めてないです。
ただ、他のクラス名などと違和感がないかつクラス名と区分するくらいで決めます。
IDは関数内で変数名として再指定して使う場合が多いので、特にJSの命名規則に揃わなくてもいいはずです。
むしろ変数名と職別できるので間違いする可能性は低くなります。

変則的にコンポーネントが追加された場合を考えてみましょう。
上記の場合では、部屋数や年齢別の人数を調整するため、number-selectorと言うコンポーネントを追加しています。

<template lang="pug">
  div.number
    table
      tbody
        tr
          td.-title {{ title }}
          td
            button.-minus -
          td.-amount
            p {{ result }} {{ type }}
          td
            button.-plus +
    input
</template>

このコンポーネントでも、最上位階層はアルファベットの小文字で始まっています。
なので、これが独立したコンポーネントであることがコード上で明らかになります。

結論

いくら有名なルールでも、いくら人気があるルールでも、今の自分の作業に合ってなかったらむしろ作業に悪影響します。
自分が得意だと押しているルールでも、細かい命名規則を追うには、プロジェクトにいきなり参加した人には分かりづらい場合も多いです。
少人数で速くルールを熟知して、短期間で成果を出したいと思いましたら、ぜひ一度お試しください。

3
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
3
Help us understand the problem. What is going on with this article?