6年前、初めてCSSを触ってからCSSモジュールを使うようになるまでの時系列

23views
サムネイル画像

WEBサイト制作を駆け出して最初に学ぶのがHTMLとCSSですが、私も例に漏れず最初はその2つから始めました。最初はProgateと書籍で勉強した記憶があります。

WEBサイト制作を6年してきて、CSSの書き方はいろんな方向に派生・発展していくことを知りましたので、それぞれ今考えていることをまとめておこうと思います。

素のCSS・フレームワーク・命名規則設計・モジュールについてそれぞれ優劣は特に考えておらず、この要件ではこれかなくらいの考えを持っています。章の順番は学んだ時系列で並べます。

普通のHTML/CSS

書いたCSSをそのままlinkタグで読み込む方法を今回”普通の”としています。

最初に作ったサイトはWordPressのテーマを改造して作ったので、教科書通りのHTML(PHP)とCSSでコーディングしました。

当時はまだギリギリ横並びデザインはfloatを使う方法を紹介している技術記事や書籍に出会えた時期で、IE対策のコーディングをしなければいけなかった記憶があります。

現在はこの”普通”スタイルは既に構築されているサイトの軽微な修正かブログ記事に少しデザインを追加したい場合など、かなり限定的な場面でしか使っていません。

Sass(SCSS)

CSSを書くときはSassを使うという情報を目にしてSassに入門しました。SassはSASSとSCSSがありますが、スタイリング記法が普通のCSSと似ていることから入門当初からずっとSCSSを使っています。むしろSASSを使っている状況を見かけたことがないような気がします。

入門当初は、VSCodeの拡張機能でSCSSをコンパイルして生成されたCSSをHTMLで読み込んでいました。

初めはファイル分割することでメンテナンス性が向上する程度の知識しかありませんでしたが、CSSアニメーションを使った数秒SVGアニメを作っていたときはSassのforをよく使った記憶があります。CSSアニメーションでは使いまわせそうな記述がよく出てくるので今でも重宝しています。

数年前までは色やフォントサイズなどのサイト共通プロパティはSCSSの変数を使っていましたが、最近はCSSカスタム変数の方がJSでアクセスできたりコンテナクエリと相性がよかったりでほとんど使っていません。

VSCodeの拡張機能がLibSassからDartSassに移行したところで拡張機能を使うのを辞め、全ての制作でWebpackでコンパイルする方法に完全移行しました。

SCSSは今もJSフレームワークを使わない制作ではかなり重宝しています。

命名規則設計(BEM)

BEMは、DOMにつけるclass名をBlock,Element,Modifiedの3つの属性に分けてつける規則ですね。

BEMの仕組みを軽く説明すると、例えば

  • 半透明カードのDOMのスタイリングの場合transparentCard
  • カードのヘッダーはtransparentCard__header
  • ヘッダーが色付きの場合はtransparentCard__header—bgColor
  • 半透明カードにボーダー付いてる場合はtransparentCard—boder

のような法則で、Blockをベースとして、ElementはBodyにアンダースコアを2つ(Body__Element)、Modifiedはハイフンを2つつけて繋げるという命名規則です。

BEMはSCSSを使い始めてすぐに学びました。というのもこの命名規則がファイル分割してインポートするSassの仕組みと非常に相性が良いためですね。

BlockごとにSassファイルを作成(上の例の場合transparentCard.scss)し、ElementとModifidedはSass記法の&で繋げる形式で記述していくことでとてもコードの見通しが良くなります。

.ExampleBlock {
  &--modified {
    // modified props
  }

  &__element {
    // element props

    &--modified {
      // element modified props
    }
  }
}

同名のファイルを同じフォルダに作成できないのでBlockをそれぞれ分割することで、クラス名が競合しないという点が特に優秀な設計だと思っています。数ヶ月の個人開発を含む複数人数の開発では、思わぬ同じ名前のクラスをつけてしまうことがあるので開発時点の手戻りも少なくなりました。

Blockはユニークな名前をつけなければいけないので、最初は命名に時間を使った記憶がありますが、このような命名はプログラミングの変数や関数などの命名にも活きている気がしています。

Blockがユニークなので、Element部分はitemtexttitleなど、一般的な名前をつけることができることも開発が楽になるメリットだと感じています。

CSSフレームワーク(Bootstrap)

ここでいうCSSフレームワークは、CDNやパッケージによってCSSをインポートして、あらかじめ決まったCSSクラスをHTMLにつけていく形式のものとしました。

例えば

  • クラス名w-100ならCSSwidth: 100%
  • クラス名text-smallならCSSfont-size: 60%
  • クラス名justify-centerならCSSdisplay: flex; justify-content: center;

のように既にクラス名にプロパティ群が振り分けられていて、どのようなデザインになるか把握していればHTMLにクラス名をつけるだけでデザインが完了するという仕組みという認識をしています。

最初に触ったのは特に有名なBootstrapでした。

それ以前はサイトのデザインはデザイン担当のたじに任せて、忠実に再現するようなコーディングをしていたので、簡単に使いやすいUIデザインを構築できるのが嬉しかった記憶があります。

速度や機能ファーストの開発ではUIの一貫性もあり非常に有効だと考えています。

ただHTMLのクラス名を見てどのような役割を持っているのかが分かりにくいので、オリジナリティが求められる中規模以上のサイト制作では採用しにくいと感じています。

React Bootstrap

ReactのライブラリとしてBootstrapを使う場合、通常の使用感以上に使いやすかった記憶があります。

Bootstrapの指定のクラスの下に置くことを想定されているクラス名のような仕様がReactコンポーネントとしてカプセル化されている部分がよりフレームワークの利点を伸ばしているように感じました。

上で書いたクラス名を見て役割を想像しにくい欠点はReactコンポーネントとしてラッピングすることで克服できており、UIの一貫性を通しながら一層メンテナンス性が向上できると考えています。

CSSモジュール

ReactやVueを触るようになってからCSSモジュールの存在を知りました。

スタイルシートは{name}.module.cssや{name}.module.scssのような名前で作成し、JSでインポートしてスタイルシート内で作成したクラスをDOMに指定します。

CSSモジュールの嬉しい点

コンポーネント単位でファイルを作ることでSCSS/BEMのような命名の競合対策とElementのように一般的な命名をすることができること

BEMの場合はBlockの名前が長くなるとHTMLにclass="highLengthNameCard__borderButton"と記述量が長くなるところ、Blockの記述を省略できること

作成したCSSはビルドするとname_class__E1Ffa3のように、{ファイル名}_{クラス名}__{ランダム値}というクラスが付与されます(形式は変更可能)。これによって別のReactプロジェクトで作成されたコンポーネントが、仮に同一CSSモジュールファイル名で同一クラス名だとしてもランダム値が異なるのでスタイリングが競合しない利点も嬉しい点ですね。

CSSモジュールのサンプル

Card.module.scss

.root {
  // カードコンポーネントのルート props
}

.content {
  // コンテンツ props
}

.submitButton {
  // 送信ボタン props

  &.loading {
    // loading中 props
  }
}

Card.jsx(React)

import style from 'Card.module.scss'; // ここでSCSSモジュールを読み込む
import React, { useState } from 'react';

export default function Card ({ children }) {
  const [loading, setLoading] = useState(false);

  return (
    <div className={style.root}>
      <div className={style.content}>
        {{ children }}
      </div>
      <button
        className={`${style.submitButton} ${loading ? style.loading : ''}`}
        onClick={() => setLoading(true)}
      >
        送信
      <button>
    </div>
  );
};

まとめ

冒頭書いた通り、それぞれの利点はプロジェクトの要件や規模や使用環境に寄るものですが、今はReact/VueとCSSモジュールでの開発が楽しいです。

カテゴリー