CSS
Elm
フロント
Elm 2Day 12

[Elm] いろいろためしたけど、もう見た目をあらわすクラス名をつけても全然いいよね?

More than 1 year has passed since last update.

Elm でどのように見た目をあつかうかについて僕がいま考えていることをまとめました。

結論として「BootStrap みたいな方針でCSSを書いて使えばいいよ」という単純な話を、

だらだら歴史的経緯とかどうでもいい話をしながら書きました。


従来の主張

まず、「見た目をあらわすクラス名を使うべきではない」と言われてきた背景をおさらいしたいと思います。

ここで言う「見た目をあらわすクラス名」とは、BootStrapのような方式のCSSフレームワークで採用している

HTMLのクラス名に col-sm-8pull-right のような見た目に関わる名前のクラスを入れる方針のことを意図しています。

従来は HTML/JS/CSS の役割を次のように分け


  • HTMLがページの構造のみを記述し

  • JSが挙動のみをあつかい

  • CSSが見た目をどう見せるかを全て制御する

こうすることで、見た目の変更をしたいときにCSSファイルのみを編集すればよく、メンテナンスがしやすいと主張されてきました。

それが理由で、BootStrapのようなCSSフレームワークは、「あきらかに見た目にかかわる記述がHTMLに入っていて、役割が分離されていないので良くない」という批判もあり、僕もその考えに則ってクラス名は極力のその要素の役割を示す menuIcon のような名前のクラスを使い、そこにスタイルを適用させてきました。


Elm の場合

The Elm Architecture にしたがってフロントエンドを作ると


  • HTMLがページの構造のみを記述し

  • JSが挙動のみをあつかい

  • CSSが見た目をどう見せるかを全て制御する

この構造のうち、HTMLとJSの垣根が消えます。

Elmファイル の中に HTML の構造(View)も、ロジック(update)も混在するようになるからです。

でも、まだ実際の見た目に関する情報(CSS)は Elm の管理外にあります。


役割をあらわすクラス名を使うことのデメリット

The Elm Architecture では、Model の状態から一意に定まる View を定義します。

ただ、実際にはこの View は「見た目」ではなく HTML の構造を記述するものです。

「HTMLは 見た目ではなく ページの 構造 を記述するものだ」という原則にのっとると、実は HTML は Viewよりも Model としての役割を持っており、

Model -> Model' (HTML) -> View (CSSを適用)

という Model が重複した構造になっています。

これって、むしろ管理しにくくありませんか?

Elmで見た目に関する情報も管理して、Model' -> View の部分を View にまとめた方がすっきりしそうです。


インラインスタイル

これを解決する方法の1つがインラインスタイルです。

つまり、タグの style 属性に直接CSSを書いてしまいます。

これなら、Elm ファイルで見た目も設定できてすっきりします。

ただ、この方法にはいくつか問題があります。

@jinjor さんがまとめてくれた内容の他にも、がっつり B to C なアプリケーションだと、auto-prefixer や postcss-flexbugs-fixes が使えないのは大きなデメリットになります。


elm-css

他の方法としてelm-cssがあります。

ただこれも問題があって、無理にCSSをElmの世界に落とし込んでいるため、独特の型に従う必要があり不自由です。

CSSに型がついていてもあまり嬉しさはありません。

だってCSSでランタイムエラーが出て止まることなんてないし、そもそもちゃんと反映されたかどうかなんて見れば明らかじゃないですか。


じゃあどうするの?

無駄にむずかしく考えずに、実は BootStrap 的な方針を使えばいいだけじゃないかというのが最近の僕の考えです。

つまり、見た目に関するクラスを事前に定義しておいて、そのクラスに対して CSS ファイルでスタイルを事前にあてておく方法です。

CSSファイル自体は別に存在しますが、実際にViewをどう見せるかという記述は Elm 内にあるため、メンテナンスがしやすくなります。

たとえば事前に以下のような CSS (SCSS) を定義しておいて...

$accent-color: #ac0000;

.column {
display: flex;
flex-direction: column;
}

.row {
display: flex;
flex-direction: row;
}

.accentColor {
color: $accent-color;
}

.expanded {
flex: 1;
}

Elm 側でこんな風にViewを定義します。

div

[ class "row"
]
[ img
[ src "/img/icon.png"
]
[]
, div
[ class "expanded"
, class "accentColor"
]
[ text "メッセージ"
]
]

みためを変えたければ、CSSは特にいじらずViewを書き換えます。

div

[ class "column"
]
[ img
[ src "/img/icon.png"
]
[]
, div
[ class "expanded"
, class "accentColor"
]
[ text "メッセージ"
]
]

View がどんな見た目なのかも管理できて、むしろこっちの方がメンテナンスが楽です。

また、チームで開発する際に、CSSをガッツリ書ける人が最初にCSSを書いておけば、あとはあまりCSSを書けない人でも単純なルールに則ってViewを書くだけなので、見た目を統一するのが容易になります。


でもそれだけじゃダメ

見た目を示すクラス名を使えばある程度まで対応できますが、例えばhoverしたときに特殊な動きをするとか、そのView専用のスタイルを当てたいみたいな場合には、見た目に関する情報を Elm 内で記述するのが難しくなります。

そこで、最近は


  • レイアウトや基本的なスタイルに関しては、BootStrapのような見た目を示すクラスを利用

  • 細かい特殊なスタイルはReusable Viewで対応

という方針をとっています。

ただ、後者について話すには余白があまりないので、また別の機会に回します。


実は Style elements の方針と一致する

僕自身は Style elementsを使ったことはないですが、

どうやら Style elements は、レイアウトについてはインラインスタイルのようにViewに直接記述するそうです。

一方で細かい見た目の調整は elm-css のような仕組みで別途管理しているようです。

スタイルについていろいろ考えると、やはりこのような方針に落ち着くのかもしれません。

P_20171025_215601_vHDR_On.jpg