(筆者は今では積極的にはこの手法を使っていません。詳しくは追記をご覧ください。)
elm-css
ライブラリのCSS生成機能とelm-css-webpack-loader
を用いることで、CSS in Elm のさまざまな恩恵にあずかれます。
はじめに
なぜ CSS in Elm が必要か
CSS in JS という言葉が、React界隈で使われるようになっていくらか経ちました。
CSS in JS は、本来 CSS で記述するスタイルを JavaScript で書いてしまうことで、名前空間やネスト構造が使えない不便なCSSから解放されることを目的にしています。
Elm で CSS in JS (Elm) を採用することで、従来のCSSによるスタイルにおける以下の問題を解決できます。
a. スタイルの記述が Elm コンポーネントとは別のファイルになって、配布しづらい
b. CSS に名前空間がないので、Elm コンポーネントを作っても、そのコンポーネントにのみ局所的にスタイルを当てるのが困難
c. その他 CSS は言語としてイケてない
これらの問題を解決しようとする他の方法に、Elm UIがあります。
Elm UI は、elm-make
に変わる独自のコマンドを採用することで a の問題を、Sass を採用することで b, c の問題を解決する方針をとっていますが、独自のコマンドを使わなければならず、"Elm UI way" に完全に染まる必要があります。
CSS in Elm に関する既存手法との比較
Elm で CSS in JS (Elm) を試みた日本語の記事としては、インラインスタイルを Elm コードで管理する@jinjor さんの記事などがありますが、今回紹介する手法は
-
elm-css
ライブラリを利用する - Elm で記述したスタイルを、コンパイル時にCSSファイルとして書き出す
点において異なり、以下のメリットを得られます。
A. 型安全なスタイル記述
B. オレオレスタイルではない、一般に認知された記述形式
C. ::after
, :hover
などの擬似要素を使える
D. メディアクエリも普通に使える
E. ページ読み込み時に、並行してCSSを読み込める
F. ランタイム速度が向上する (インラインスタイルを当てるためのDOM操作が不要なため)
G. auto-prefixer, flexbugs-fix など、PostCSS の資産をそのまま使える
一方で、@jinjorさんの手法と比較した場合に、以下のデメリットがあります。
-
elm-css
の記述方法を学習するコスト -
elm-css
がメンテナンスされなくなるリスク - 動的な値を使うことができない
他にも差異があるかもしれませんが、ご自身の用途に応じて最適な手法をお選びください。
余談: CSS in Elm に関わる歴史
実は、React 界隈で CSS in JS という言葉が出てくるよりも前から、Elm は CSS in Elm 的な考えを持っていました1。
その後、elm-html
ライブラリの出現によって、「CSSを直接書くことができない」という、とがった方針はいったん転換されるのですが、elm-css
の背景にある思想は、この記事にあるものに似ているのではないかと推測しています。
elm-css + elm-css-webpack-loader による解決方法
基本的な elm-css
の使い方は、githubのREADMEを見れば、とくに困らないと思うので、詳しくはここでは述べません。
elm-css
の使い方には、大きく2つの方法があります。
- インラインスタイル
- CSSファイルを事前に生成する
1を採用すると、前述の@jinjorさんの記事とほぼ同じことが可能になります。
以下のメリットだけで良い場合は、こちらを選ぶと良いでしょう。
A. 型安全なスタイル記述
B. オレオレスタイルではない、一般に認知された記述形式
2を採用することで、メリットC,D,E,F が得られます。
しかし、elm-css
のみをつかっていては、
G. auto-prefixer, flexbugs-fix など、PostCSS の資産をそのまま使える
を享受することができません。
これを可能にするのが、elm-css-webpack-loader
です。
elm-css の issueから生まれました。
この webpack-loader によって、elm-css
で記述したスタイルを CSS に変換、webpackによってPostCSSなどの処理を加えることができます。
ただ、elm-css-webpack-loader
の /example
コードが最新の Elm 0.18 に対応していなかったり、改善の余地があったため、より良いサンプルを用意しました。
elm-chat-scenario のサンプルを動かす
今回作成したサンプルは、github のレポジトリに置いてあります。
このレポジトリは、Conversational User Interface (チャットボットなどの根底にある思想) を型安全に実現するために作ったものです。
CSS in Elm によって作成されたデモ をご覧ください。
まだUIが荒削りですが、CSSを使わずにスタイルを記述し、flexbugs-fix や auto-prefixer を使っています。
このライブラリの構成は以下のとおりです。
src
├── Scenario
│ ├── ChatUI
│ │ └── Css.elm
│ └── ChatUI.elm
└── Scenario.elm
Scenario.elm
に、UIとは独立したコアとなる機能を、Scenario/
以下に、ライブラリ利用者がすぐに使える便利なUIを配置する構成です。
今回のメインテーマである Elm in CSS は、Scenario/ChatUI/Css.elm
に記述されています。
次に、デモとしてお見せしたサンプルアプリのソース構成です。
sample/chat-ui/src
├── elm
│ ├── HomepageView.elm
│ └── Stylesheets.elm
├── index.js
└── index.pug
HomepageView.elm
は、Elm Architecture にしたがって、Scenario.ChatUI
のUIを組み込んでいるだけです。
Stylesheets.elm
が、Scenario.ChatUI.Css
を読み込み、npm run build
でコンパイルした際に、CSSファイルを書き出します。
sample/chat-ui/webpack.config.js
に webpack の設定ファイルが置いてあるので、ご参照ください。
elm-webpack-starterを参考に、npm start
でホットリロードしながら開発できるようにもしています。
まとめ
以上、elm-css
のCSSファイル書き出し機能とelm-css-webpack-loader
の合わせ技で、PostCSSなどの便利な機能を使えるようにしつつ、スタイルをElmコードと一緒に配布する方法について、他の手法と比較しながら簡単にご紹介しました。
正直なところ、elm-css
を使ったCSS記述は、Sassで書くのに比べてめんどうです。
ただ、それでも、一般に認知された共通のルールでスコープ付きのスタイルを記述し、Elm プログラムとともに配布できるのはメリットが大きいと思います。
追記
この手法も結構メリットがあるんですが、elmの文法で型安全にCSSを書くために独自の記法に従わないといけません。
elm-css の主張としては「CSSを型安全に書ける」ということなのですが、正直CSSに型安全なんていらないというのが現在の僕の考えです。
だって、プログラムだったら100年に1度しか実行されないようなコードにバグを残す可能性があるので型安全にしてコンパイル時にtypoなどを検知することに大きなメリットがありますが、CSSですよ? typoとかしてもブラウザ上でチェックして普通はすぐ分かるじゃないですか。
たったそれだけのために毎度packageを検索して「あれ〜 background-color
のプロパティはどうやって指定するんだっけな?」って探すのは工数に見合わないと思うんです。
ということで、現在は単純に Sass (SCSS) で別ファイルにスタイルを記述する方法と、elm-css-modules-loader を併用しています。
elm-css-modules-loader
はちょっとイケてない設計をしていたり、githubのissueがまともに機能していなかったりするので、いつか yet-another-elm-css-modules-loader
を作ろうと思いつつ無情にも時間が過ぎています。
追記2
さらに最新の方法を記事にしました。
「ElmにクリーンでハックのないCSS modulesを」
「Elmでもっと気軽にCSS modules」
-
vjeux 氏のスライドよりも前にこの発表をしている ↩