Help us understand the problem. What is going on with this article?

elm-css で PostCSS も使える CSS in Elm

More than 1 year has passed since last update.

(筆者は今では積極的にはこの手法を使っていません。詳しくは追記をご覧ください。)

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つの方法があります。

  1. インラインスタイル
  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」

Df-s7diV4AA_7bj.jpg:large.jpeg
さくらちゃんにご飯をあげる


  1. vjeux 氏のスライドよりも前にこの発表をしている 

Why do not you register as a user and use Qiita more conveniently?
  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
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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