Rails with WebpackerにTailwind CSSを導入する

先日Railsでイチから個人開発を始めたんですが、CSSフレームワークとしてTailwind CSSを使ってみました。
その時得た導入方法の知見としばらく使ってみての感想。

ちなみに僕はHTMLとCSSはセマンティックに書くべし、というスタンスには賛同しています。つまり、これまではTailwindのアプローチ
について懐疑的でした。

概要

  • RailsでTailwind CSSを使ってみようと思った
  • Webpacker前提として導入してみた
  • この前提で考えると相性はなかなか良好、想像してたより良かった
    • Tailwindについての感想

Tailwind CSS is何?

Tailwind CSSはBootstrapやBulumaなどと同様、HTMLにあらかじめ設定されたクラスセレクタをつけるだけでCSSをほとんど書くことなくスタイリングができるCSSフレームワークの一種です。

しかし、TailwindはBootstrapなどのCSSフレームワークとは逆の発想で、セマンティックなCSSを諦め、Utility FirstなCSSフレームワークとしているのが特徴です。このアプローチについては時間があれば是非『CSS Utility Classes and "Separation of Concerns"』(翻訳)を読んでいただきたいところです。

動機

いつもCSSは自分でフルスクラッチで書く派なんですが、ハッカソンスタートということもあり時間かけずにやりたかった理由が1つ。そして上で紹介したなぜTailwind CSSがUtility Firstというアプローチに辿りついたかを読んでみて興味がわき、まずは試してみようと思いました。
イチから新しいプロジェクトで作るのと、ちょうどタイミングが良かったんですね。

もうひとつはJSに頼らないCSSだけのフレームワークなので、WebpackerやRailsとの相性も良さそうに思ったのも一因です。とにかく使ってみないことには始まりません。

期待してたこと

まず、Rails with Webpackerという事情でもちゃんと不足なく動作すること。そして開発が継続しても辛くないこと。たくさんのスタイルを設定してもハック的な処置なく使えること。

このへんが使いつづけるにあたって注意すべきポイントですね。

実際の導入手順

Railsのプロジェクトができていて、Webpackerがinstallされているところを前提として解説していきます。
まずライブラリを入れます。今回はWebpakcer前提なのでYarnで説明しますが、NPMでも同様なのでそこは適宜読み変えてください。

$ yarn add tailwindcss

入れたら、initします。具体的には設定ファイルであるtailwind.config.jsを作る操作です。

$ yarn tailwindcss init

# optional
$ mv tailwind.config.js app/javascript/css

プロジェクトルートでもかまいませんが、css用のディレクトリがあればそこに置くほうがわかりやすいので移動しておきます。以後、移動した前提で書きますのでパスには注意してください。

次はapp/javascript/csstailswind.cssというCSSファイルを作り、以下のように記載します。

@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

ライブラリからimportするだけですね。

Webpackerを使う前提ならプロジェクトルートにpostcss.config.jsがあるので以下のようにします。

const environment = {
  plugins: [
    require("tailwindcss")("./app/javascript/css/tailwind.config.js"),
    require("autoprefixer"),
    require('postcss-import'),
    require('postcss-flexbugs-fixes'),
    require('postcss-preset-env')({
      autoprefixer: {
        flexbox: 'no-2009'
      },
      stage: 3
    })
  ]
}

if (process.env.RAILS_ENV === "production") {
  environment.plugins.push(
    require('@fullhuman/postcss-purgecss')({
      content: [
        './app/**/*.html.erb',
        './app/**/*.html.slim',
        './app/**/*.js.erb',
        './app/helpers/**/*.rb',
      ],
      whitelist: ['img', 'video', ':root'],
    })
  )
}

module.exports = environment

設定によって多少異なりますが、おおむねこんな感じですね。
着目すべき点は、require("tailwindcss")("./app/javascript/css/tailwind.config.js"),でconfigを指定しているところ。

またPurgecssで最終的なCSSのサイズを減らそうと思ってるので設定を書いておきます。whitelistにはひとまずimgとかを入れておきました。Railsの場合image_tagなどのヘルパーメソッドで<image>タグを扱うことも多いので、whitelistに指定しておかないとpurge対象になってしまいます。

それでは前述したPurgeCSSを入れます。これはUtilityFirstが故にTailwind CSSは数多くのCSSが設定されています。使わないもの、組み合わせも多数あるのでPurgeCSSを用いて使わないものはコンパイル対象から外して軽くします。

yarn add @fullhuman/postcss-purgecss

設定は上記で先に書いちゃったので特になにもしなくてOKです。もちろんお使いの環境に合わせて適宜調整はしてください。

そしてTailwind CSSがデフォルトのままでは足りずカスタムする必要がある場合、app/javascript/css/tailswind.config.jsを編集します。

例えばカラーパレットが用意されたもの以外に必要になった場合や、Tailwind用のプラグインが必要になった場合を紹介します。以下の例はカラーパレットの追加、tailwindcss-textshadowプラグインの追加をしています。事前に

$ yarn add tailwindcss-textshadow'

しておいてください。そして設定は

module.exports = {
  purge: [],
  theme: {
    extend: {
      colors: {
        sp: {
          'lightest': '#f9f4ef',
          'lighter': '#eaddcf',
          'darker': '#8c7851',
          'darkest': '#716040',
          'accent': '#f25042',
          'white': '#fffffe',
          'black': '#211308',
        }
      }
    },
  },
  variants: {},
  plugins: [
    require('tailwindcss-textshadow'),
    function ({ addUtilities }) {
    const newUtilities = {
      ".text-shadow-bold": {
        textShadow: "0px 2px 3px black"
      },
    }
    addUtilities(newUtilities)
  }],
}

のようになります。カスタムの詳細についてはConfiguration - Tailwind CSSやそのセクションの他の項目を参照すると良いでしょう。

これで導入設定自体は終わりです。
あとはerbslimで書かれたRails用のHTMLテンプレートにTailwind CSS用のクラスセレクタを追加していけばOKです。

やってみた結果

結果として、特に問題なく動作しています。良かったです。

Tailwind CSSをつかってみてわかったのは、想像より使い勝手良く、楽ですね。ただしクラス名はCSSプロパティに依存した命名なので、CSSの知識自体が少し必要かもしれません。また、セマンティックではないので、自分の手で細かくスタイルを決めていかないといけない、また意味的な可読性が落ちる、クラスセレクタの記述量増加などの弊害もあります。

とはいえ、最低限のCSSの知識でガリガリ書いていけるし、ちゃんとしたCSS知識があれば複雑なものも自由に書けちゃいます。フルスクラッチとコンポーネント的なCSSフレームワークの良い中間、という感じ。

細かく設定できるので、痒いところに手を屆かせるために自分で上書きするようなCSSを書かなくていいですし、スタイルを書くときにERBやSLIMなどのHTML側とCSSを行き来しなくていいのも楽でいいですね。

成果物

導入して使ってみた成果としては、

を見てみてください。
どうしてもCSSを書かなきゃいけないところは書いていますが、全体で50行も書いておらず、ほぼ全てをTailwind CSSでのスタイルでまかなっています。

感想

今回はRails with Webpackerの環境にTailwind CSSを導入してみました。

問題なくフルに動いていてくれるのに加え、想像してたよりTailwind CSSの使い勝手が良くて嬉しかったです。
特に今回のようなフルスクラッチするまでもないが、そこそこゴリゴリ書きたい場合に相性が良いですね。
また、その状況はフロントが完全に切り離されてないWebpacker環境でわりと多いのですんなり導入できるのは心強いです。

逆に言えば管理画面のような要件だとUI系のライブラリのほうが生きるかもしれません(ただし、Tailwind UIも開発中なので今後どうなるか楽しみ)。フロントエンドを完全に切り離してReactやVue.jsを使うのならScopedなCSSを書くだろうし、Tailwindの出番は少なそうですね。

また、フルスクラッチ寄りになるので配色や太さ、レイアウト、余白などのデザインセンスも問わやすいです。ただし、このへんも探せばたくさんサンプルがありますし、逆に言えばライブラリの癖に引きづられず自分の好きなように組めるのが利点でもあります。

ということで今回実際につかってみてTailwind CSSをかなり気に入りました。そしてUtilityFirstの思想と実際の効果も理解できました。これはフルスクラッチで書ける人ほど上手く使えると感じました。
なにか困っても公式ドキュメントにはclassに対してどのようなCSSが当たってるかちゃんと書いてあるので、そのクラスを追加するだけでいけちゃいます。

要件次第ですがたぶん今後も同様の要件な場合、積極的につかっていきたいと思いますです。

褒めLTに参加して個人開発のエモい発表をしてきた顛末web1weekに参加して「Achievementalist - リアルライフ実績解除」というサービスをリリースした顛末