UIkitのバージョン3.0(beta)のカスタムテーマをSassで定義する

UIkitのスタイルシートのソースコードはLess版とSass版とがあります。   カスタムテーマを作成する環境としてはLessの方が充実している印象を受けます。(カスタムテーマ作成のドキュメント量もLessの方が多いので) Ruby on Railsで利用するにはどちらで作成しても生成されたCSSファイルを適用する方法があると思います。というかそれで十分です。

ですが、今回は敢えてScssでカスタムテーマを作成することにしました。ゴールとしてはScssで定義したカスタムテーマをRailsに適用するところまでにしたいと思います。

実はless-railsというgemもあるので、おそらくこれを適用することでLessでカスタムテーマを作成することができるのかもしれません。しかし、Railsが標準的に採用しているのがScssなので、一度Scssでのカスタマイズ手順を確認しておきたいと思います。


何をどこまで実施すれば良いのか

私はCSSの仕様についてはそれなりに理解しているつもりですが、Scssについてはあまり知識がありません。
ですのでRailsに組み込もうとする場合に必要な設定や、まさに適用するスタイルシートのファイルをどう準備するのか。この辺りから手探りではじめてみることにします。

sass-rails

まずgem saas-railsのドキュメントを確認すると https://github.com/rails/sass-rails#important-note に重要事項が記載されています。
*= requireなどで指定するのではなく、@importを利用してインポートしなければならないようです。

では早速試してます。   管理画面のテーマを想定してadmin-theme.scssを作成します。 app/assets/stylesheets/admin-theme.scss

#main {
  width: 97%;

  p, div {
    font-size: 1.5em;
    a { font-weight: bold; }
  }

  pre { font-size: 0.8em; }
}

app/assets/stylesheets/application.cssを次のように変更します。
(記載していませんがrequire_tree .などは = を削除して無効にしておきました)

なおapplication.cssで @import を使用する場合には拡張子をscssに変更しておく必要があります。

  @import 'admin-theme.scss';

取り急ぎwelcomeページを自動生成して、若干手を加えました。

<h1>Welcome#index</h1>
<p>Find me in app/views/welcome/index.html.erb</p>
<pre>Find me in app/views/welcome/index.html.erb</pre>
<div id="main">
  <p>Find me in app/views/welcome/index.html.erb</p>
  <p><a href="#">Find me in app/views/welcome/index.html.erb</a></p>
</div>

結果は次の通り

画面


UIkitの導入

Sassが利用できること(当然なのですが)を確認できましたので、UIkitを導入してみます。

npm / yarnで導入

UIkitのドキュメント ではnpmコマンドでのインストール方法が紹介されていますが、webpackerを導入したRailsプロジェクトでは yarnも利用できるのでyarnコマンドでインストールしてみます。
yarnは事前にインストールしておく必要がありますが、ここではyarnの導入については割愛させていただきます。

$ yarn add uikit --save
yarn add v1.3.2
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning "@rails/webpacker > postcss-cssnext@3.1.0" has unmet peer dependency "caniuse-lite@^1.0.30000697".
warning " > webpack-dev-server@2.11.2" has unmet peer dependency "webpack@^2.2.0 || ^3.0.0".
warning "webpack-dev-server > webpack-dev-middleware@1.12.2" has unmet peer dependency "webpack@^1.0.0 || ^2.0.0 || ^3.0.0".
[4/4] 📃  Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
└─ uikit@3.0.0-beta.41
✨  Done in 11.97s.

これで node_modules/uikit が追加されました。   アセットのプリコンパイルの対象となるように uikit のパスを追加する必要があります。   https://github.com/rails/sass-rails/issues/414
にIssueとして登録されていましたので、解決策の通り設定を行ってみます。

・・・すでに config/initializers/assets.rbに

Rails.application.config.assets.paths << Rails.root.join('node_modules')

が設定されていました。


UIkitのインポート

では node_modules/uikit を import してみましょう。

先ほど作成した admin-theme.scssを UIkitのサイトに記載されている内容に変更します。

// 1. Your custom variables and variable overwrites.

$global-link-color: #DA7D02;

// 2. Import default variables and available mixins.

@import "uikit/src/scss/variables-theme.scss";
@import "uikit/src/scss/mixins-theme.scss";

// 3. Your custom mixin overwrites.

@mixin hook-card() { color: #000; }

// 4. Import UIkit.

@import "uikit/src/scss/uikit-theme.scss";

画面をリロードすると次のように変わりました。

画面

UIkitのデフォルトのテーマと、カスタマイズしたリンクの色が適用されたことが確認できました。


JavaScriptの設定

UIkitはGridレイアウトをはじめ多くのコンポーネットも揃っていますが、これらはJavaScriptを利用してます。
イニシャライザーの config/initializers/assets.rb に node_modulesのパスが設定されていますので、JavaScriptをロードするための設定は次のように実施しました。

app/assets/javascripts/application.jsにUIkitのJavaScriptのパスを追記。

//= require rails-ujs

//= require turbolinks

//= require_tree .

//= require uikit/dist/js/uikit.min

//= require uikit/dist/js/uikit-icons.min.js

まとめ

カスタマイズしたスタイルを適用する方法を確認することができました。   実際に求められるテーマに仕上げるにはさらに多くの設定を行う必要がありますが今回はここまでとし、一旦手順をおさらいしておきます。

  • UIkitのライブラリをインストール
    npm もしくは yarn で導入

  • アセットのパスを設定する   Rails.application.config.assets.paths
    今回の環境はすでに node_modules が追加されていましたが、別のディレクトリに保存した場合などは適切なパスを設定しましょう。

  • UIkitが提供しているテーマのインポート application.cssがimportできるパスにscssを作成して、デフォルトのテーマをインポートする。   今回は admin-theme.scssというファイルを作成しました。

  • カスタマイズ
    既存の変数の上書き、mixin を利用してカスタマイズを行う。

  • application.cssにscssファイルをインポート application.cssは拡張子がcssでも@importは機能したようです。 scssにした方が良いという記事も見かけますのでscssに変更しておいた方が良いかもしれません。(今回はcssのままでも問題なかったようですが)


おまけ

@mixin hook-card()がどうなっているのか確認してみます。

UIkitにはuk-cardクラスのスタイルが用意されており、componentのcard.scssに次のように設定されています。

.uk-card {
    position: relative;
    box-sizing: border-box;
    @if(mixin-exists(hook-card)) {@include hook-card();}

hook-cardというmixinが見つかればそれをincludeするという処理のようです。

uk-cardにはuk-card-defaultやuk-card-primaryなどのスタイルも用意されていますが、 これらを指定してしまうと後から設定が上書きされてしまうため、このmixinが適用されなくなってしまうようです。

uk-cardのみでしたらhook-cardに設定した内容が反映されていました。
また、Gridレイアウトも追加しました。

画面

app/views/welcome/index.html.erb

<h1>Welcome#index</h1>
<p>Find me in app/views/welcome/index.html.erb</p>
<pre>Find me in app/views/welcome/index.html.erb</pre>
<div id="main">
  <p>Find me in app/views/welcome/index.html.erb</p>
  <p><a href="#">Find me in app/views/welcome/index.html.erb</a></p>
</div>

<div uk-grid>
  <% 3.times do %>
  <div class="uk-card uk-width-1-3@m">
    <div class="uk-card-header">
      <h3>Card Header <i uk-icon="icon: heart"></i></h3>
    </div>
    <div class="uk-card-body">
      <span>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
        sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
        Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip.
      </span>
    </div>
  </div>
  <% end %>
</div>