CSSって実はモジュールシステムが表現できるって話

前置き

css....
エンジニアは大嫌いですよね。
今でこそ、UIフレームワークがあるからいいですが
昔、自分で書くってことをやっていた時は、
本当IEに匹敵するほど嫌いでした。

さて、そんなエンジニアに嫌われ者なCSSですが
実は、node.jsやpython
importだとかexportだとかプログラミング言語にある
モジュールシステムのような物を表現する事ができるんです。

と大層なことを言いましたが
UIフレームワークが数数多存在している昨今
もはや、ネタです。

へぇ、なるほどCSSってこんな事も表現できたんだくらいに受け止めて下さい。

CSSのクラス名がプログラミング言語の関数の様だったらいいのに...

CSSを自力で書いていくような案件がある度に思います。

「この、今htmlタグのclass属性に
書いているクラス名がプログラミング言語の関数の様だったら...」

こんな感じに

<div class="grid(4,10px,30px)"></div>

ん?待てよ
出来ないのか?

そりゃCSSプログラミング言語では無いから
sassでループさせて必要なパターンを全て書き出しておく必要はあるんだろうけど...
そもそもCSSのクラス名で使える文字、使えない文字ってどういう感じなんなんだろうか?

CSSのクラス名って大概どんな文字でも使える!?

そう思って色々調べてみることに
するとこんな記事が
https://iwb.jp/css-id-class-name-zenkaku-kigou/

なんと、CSSのクラス名って日本語も使えるんだとか
マジか...

そんで記事を読み進めると
一つの希望の光が

.C\+\+ {
  color: #F00;
  font-size: 3em;
}

なんと「+」などの記号も「\」をつけてやると使えるとのこと

CSSのクラス名に記号を使ってみる

それじゃ早速CSSのクラス名に記号使ってみよう
とりあえずhtml用意

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>demo</title>
  <link rel="stylesheet" href="./main.css">
</head>
<body>
  <h1>テスト</h1>
</body>
</html>

すると現時点でこんな感じ


https://i.imgur.com/D83OxgL.png

これをとりあえず赤文字に変えてみる
クラス名はまぁオブジェクト指向っぽく
desktop.text(red,5rem)とかでいってみようかと

.desktop\.text\(red\,5rem\){
  color: #f00;
  font-size: 5rem;
}

さて、ではこのクラスを
htmlタグに適応させます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>demo</title>
  <link rel="stylesheet" href="./main.css">
</head>
<body>
  <h1 class="desktop.text(red,5rem)">テスト</h1>
</body>
</html>

ブラウザで確認して見ると...


https://i.imgur.com/UTeCp2A.png

おぉ!見事スタイルが適応されています。
ということはCSSオブジェクト指向や関数の形式で書こうと思えば書ける
と言うことです。

モジュールシステムを再現してみる

ここまでくればプログラミング言語のモジュールシステムを再現するのも
そう無理な発想でも無いです。

まず、node.jsとかのimport

import hoge from 'hoge'

これは、まぁCSSファイルでimportするという訳ではなく
htmlにimportするという発想ですね。
これは単純にlinkタグで読み込むだけです。
最後のまとめのところで紹介しているサンプルから抜粋ですが
こんな感じ

<link rel="stylesheet" type="text/css" href="/assets/css/modules/index.css">
<link rel="stylesheet" type="text/css" href="/assets/css/modules/desktop/grid.css" media="screen and (min-width: 768px)">
<link rel="stylesheet" type="text/css" href="/assets/css/modules/desktop/spacer.css" media="screen and (min-width: 768px)">
<link rel="stylesheet" type="text/css" href="/assets/css/modules/mobile/grid.css" media="screen and (max-width: 767px)">
<link rel="stylesheet" type="text/css" href="/assets/css/modules/mobile/spacer.css" media="screen and (max-width: 767px)">

ルールとしては
modules/パッケージ/モジュール
っていう感じです。
パッケージは必ずデバイスになります。
バイス共通はmodules/index.cssに入れる

また、モジュール.css内では一切メディアクエリを使ってはいけないというのもルールです。
必ず、linkタグの方で設定します。

余談ですが
昔は、grid.col()とかgrid.gutter()とか
バイス以外をオブジェクトとするアイディアも考えてましたが
結局、cssというのはオブジェクト指向よりも関数形式の方が相性が良く
バイス以外でオブジェクト指向で書くと整理がつかなくなり、
結局カオスになるという事が分かったので
最終的にデバイス区切りになりました。

続いてモジュール.cssの書き方ですが下記の様に先頭には必ずデバイス名(パッケージ名)を付けます。

modules/desktop/grid.css

.desktop\.grid\(#{$cols}\,#{$cgap}\,#{$rgap}\){ }

marginとかpaddingはspacerという名前でまとめてしまってもいいので
バイス名の後は必ずモジュール名でなければならないという事ではないですね。
ですがオブジェクト名は必ずデバイスです。

.desktop\.margin\(top\,#{$i * 5}\){
  margin-top: #{$i * 5}px;
}

.desktop\.padding\(top\,#{$i * 5}\){
  padding-top: #{$i * 5}px;
}

これらは、あえてnode.jsで書くとこんな感じですかね?

export const desktop = {
  margin(){},
  padding(){}
}

まとめ

以上、CSSでモジュールシステムを再現してみるとこんな感じですかね。
命名規則とかルールが書いている内に崩壊するのが
CSSと言うものですが、モジュールシステムで書くとこうも整理がつきます。
ルールも破り用がないほど堅牢です。
実際、書くときはsassのループを使うのがオススメですね。

とは言え、冒頭でも述べたように
UIフレームワークが様々あるこのご時世
所詮、ただのネタです!www

なので試してみたい方は
まぁ、こんな発想もあるんや程度に面白半分で試してみてください。

サンプルリポジトリあります。
依存関係インストールして
npm startでOK!