Improve this

テーマのカスタマイズ

Onsen UIの見た目は、CSSコンポーネントによって定義されています。Onsen UIを利用する時、次のCSSを必ず読み込んでいると思いますが、これがOnsen UIのCSSコンポーネントです。

<link rel="stylesheet" type="text/css" href="path/to/onsen-css-components.css">

Onsen UIのデフォルトの見た目を変更するには、このCSSコンポーネントをカスタマイズして下さい。Onsen UIのCSSコンポーネントは、SassやLessのような独自のCSSメタ言語ではなく、標準化されている文法を持つcssnextによって記述されているのでCSSさえわかっていれば誰でもカスタマイズすることができます。

screenshot

このページでは、CSSコンポーネントのカスタマイズ方法について紹介します。

セットアップ

CSSコンポーネントのソースコードは、複数のCSSファイルによって構成されています。これらのCSSファイルは、ビルドすることで一つのCSSファイル(onsen-css-components.css)にすることができます。ここではまずビルドするためのセットアップの手順を紹介します。

まず、npmを使ってOnsen UIのパッケージをインストールします。プロジェクトのディレクトリにnpmのパッケージファイル(package.json)がない場合には、npm initを実行してパッケージファイルを作成して下さい。

$ npm init # package.jsonが無い場合

次にonsenuiパッケージをインストールします。onsenuiパッケージのバージョンは自身が利用しているOnsen UIのバージョンに合わせて下さい。

$ npm install onsenui

$ npm install onsenui@2.7.0 # バージョンを指定する場合

onsenuiパッケージがnode_modulesディレクトリにインストールされるので、パッケージのcss-componentsディレクトリに移動します。

$ cd node_modules/onsenui/css-components-src

次にyarnを使って依存するパッケージをインストールします。yarnをインストールしていない場合は、yarnのインストール手順を参照して下さい。

$ yarn install --pure-lockfile

無事依存するパッケージを解決できたら、次のコマンドを実行してプレビュワーを起動して下さい。

$ yarn run serve

$ npm run serve # もしくはこちら

もし利用するOnsen UIのパッケージのバージョンがv2.7.0よりも前の場合には、yarn run serveではなくgulp serveを実行して下さい。

$ npm install -g gulp

$ gulp serve

するとビルドが始まり、成功すると次のようなメッセージが表示されます:

...
[15:37:02] Finished 'build' after 5.25 s
[15:37:02] Starting 'serve'...

Access URLs:
     Local: http://localhost:4321/
  External: http://(IP Address):4321/

Built CSS Files:
  ./build/onsen-css-components.css

http://localhost:4321/をウェブブラウザで開くとCSSコンポーネントのプレビュー用のUIが表示されます。

screenshot

モバイル端末でプレビューを確認するには、プレビューを動かしているPCとモバイルを同じネットワークに接続した上でモバイル端末のウェブブラウザでコマンドラインに表示されたhttp://(IP Address):4321/を開いて下さい。

プレビューを起動するのではなく、単にCSSコンポーネントを一度だけビルドする場合には次のコマンドを実行して下さい:

$ yarn run build

$ npm run build # もしくはこちら

カスタマイズ

先程のyarn run serveコマンドを実行している状態でCSSファイルを編集すると、CSSファイルが自動的にビルドされ、プレビューに新しくビルドされたCSSがインジェクトされて即座に反映されます。開発者がCSSコンポーネントをカスタマイズする場合には、この状態でコンポーネントの見た目を確認しつつ、個別のCSSファイルを編集していくことになります。

css-componentsディレクトリ以下は次のようなディレクトリ構造になります:

css-components
├── build
├── misc
├── node_modules
├── previewer-src
└── src
    ├── components
    └── img

src/componentsディレクトリ以下に、Onsen CSS Componentsを構成するCSSファイルなどが収められています。

プレビューを起動した状態で、試しにSwtichコンポーネントのCSSファイル(src/components/switch.css)を編集してみましょう。するとyarn run serveを実行しているコマンドラインでは次のようなメッセージが表示され、CSSが自動的にビルドされプレビューにも反映されます。

[17:07:44] Starting 'css-clean'...
[17:07:44] Finished 'css-clean' after 7.94 ms
[17:07:44] Starting 'stylelint'...
[17:07:45] Finished 'stylelint' after 1.33 s
[17:07:45] Starting 'cssnext'...
[17:07:45] Finished 'cssnext' after 257 ms
[17:07:45] Starting 'cssmin'...
[17:07:46] Finished 'cssmin' after 453 ms
[17:07:46] Starting 'build-css'...
[17:07:46] Finished 'build-css' after 8.11 μs
[17:07:46] Starting 'generate-preview'...
[17:07:46] Finished 'generate-preview' after 156 ms

Access URLs:
     Local: http://localhost:4321/
  External: http://192.168.100.100:4321/

Built CSS Files:
  ./build/onsen-css-components.css

もしCSSの文法が間違っている場合にはコマンドライン上にエラーが表示されます。 カスタマイズしたCSSコンポーネントを自身のプロジェクトで利用する場合には、./build/onsen-css-components.cssのファイルを自身のプロジェクトのフォルダ内にコピーして利用して下さい。

色の変更

src/theme.cssには、CSSコンポーネント内で利用する色の変数(CSS Variables)が定義されています。

:root {
  --background-color: #efeff4;
  --text-color: #1f1f21;
  --sub-text-color: #999;
  --highlight-color: #0076ff;
  --second-highlight-color: #25a6d9;
  --border-color: #ccc;
  ...

この変数の定義を変更することで、CSSコンポーネントで利用する色を変更できます。Material Design用のコンポーネントで利用している変数は、変数名にmaterialプレフィクスがついています。iOS用のコンポーネントで利用している変数には、プレフィクスは付きません。

:root {
  (...)
  --material-notification-background-color: #e91e63;
  --material-switch-active-thumb-color: #009688;
  --material-switch-inactive-thumb-color: #f1f1f1;
  --material-switch-active-background-color: #77c2bb;
  --material-switch-inactive-background-color: #b0afaf;
  --material-range-track-color: #bdbdbd;

CSSの設計規約

初めてCSSコンポーネントのソースを見る人は、CSSのクラス名が醜くでたらめな命名規則によって記述されているように見えるかもしれません。

例えば、src/components/switch.cssを見てみましょう。このCSSファイルに記述されているSwitchコンポーネントのクラス名には、--__によって区切られた冗長に見えるクラス名を使っていることがわかります。

.switch
.switch__toggle
.switch__input
.switch__handle
.switch--active__handle
.switch--material__toggle
.switch--material__input

しかし安心して下さい、Onsen UIのCSSコンポーネントは設計を堅牢にするために、かつ高速なCSSセレクタの記述をするために、設計規約と命名規則にBEMMindBEMdingを採用しています。

BEMでは、クラスはBlock, Element, Modifierの三つの構成要素によって記述されます。Blockは、ある独立するグループの境界を宣言します。ElementはあるBlockの配下の要素を表現します。ModifierやBlockやElementを修飾するのに用います。

次のSwitchコンポーネントを例に説明します。

Switchコンポーネント

<label class="switch">
  <input type="checkbox" class="switch__input">
  <div class="switch__toggle">
    <div class="switch__handle"></div>
  </div>
</label>

まずいちばん外側の要素では、クラス属性にswitchが宣言されています。その下にはswitch__inputswitch__toggleswitch__handleが配下の要素のクラス属性で宣言されているのがわかります。ここでは、switchがBlockで、switch__inputswitch__toggleswitch__handleがElementを表現しています。MindBEMdingでは、Block名とElement名の区切りには__を用います。

この設計規約について詳しく知りたい場合は、BEMMindBEMdingの解説を参照して下さい。

プレビューの変更

個別のCSSコンポーネントのプレビューは、CSS内に埋め込まれたアノテーションに基づいて生成されています。例えば、Switchコンポーネントのプレビューは、次のような画面になります:

スクリーンショット

このプレビューに用いられているHTMLのコードは、src/components/switch.cssに埋め込まれている次のアノテーションで定義されています:

/*~
  name: Switch
  category: Switch
  elements: ons-switch
  markup: |
    <label class="switch">
      <input type="checkbox" class="switch__input">
      <div class="switch__toggle">
        <div class="switch__handle"></div>
      </div>
    </label>
    <label class="switch">
      <input type="checkbox" class="switch__input" checked>
      <div class="switch__toggle">
        <div class="switch__handle"></div>
      </div>
    </label>
    <label class="switch">
      <input type="checkbox" class="switch__input" disabled>
      <div class="switch__toggle">
        <div class="switch__handle"></div>
      </div>
    </label>
*/

アノテーションはCSSのコメント内部にYAMLで埋め込まれています。もしCSSコンポーネントのプレビューで用いるHTMLを変更したり、プレビューを増やしたい場合にはアノテーションを編集したり新たに埋め込むことができます。

yarn run serveを実行している状態であれば、このアノテーションの変更も即座にプレビューUIに反映されます。

パターンのカスタマイズ

パターンページ

Patternsページでは、幾つかのCSSコンポーネントを組み合わせた画面の表示を確認することができます。テーマをカスタマイズする際にこのページを見ながら調整すると便利です。ここではこのパターンのカスタマイズ方法について説明します。

パターンとして表示されるHTMLは、css-components/patterns.yamlファイル内に記述されています。

---
name: Basic
markup: |
  <div class="page">
    <div class="toolbar">
      <div class="toolbar__left"><span class="toolbar-button">Label</span></div>
      <div class="toolbar__center">Title</div>
...

Patternsページで表示されるパターンのHTMLを修正したい場合には、このpatterns.yamlを編集して下さい。プレビューを起動しているときにこのpatterns.yamlを編集すると、CSSファイルに変更を加えたときと同様に自動的に反映されます。

別のテーマを追加

Onsen UIのデフォルトのテーマをカスタマイズするのではなく、別のテーマを追加する方法を説明します。

src/(任意の単語)-onsen-css-components.cssというファイルを追加して下さい。追加したCSSファイルはビルドのエントリーポイントのひとつになります:

@import url('./license.css');
@import url('./yet-another-theme.css');
@import url('./components/index.css');

さらにsrc/yet-another-theme.cssファイルを作成します。内容はsrc/theme.cssファイルからコピーしてください。

yarn run serveでプレビューを起動してビルドが完了すると、次のように表示されます。buildディレクトリにyet-another-onsen-css-components.cssがビルドされていることがわかります。

Built CSS Files:
  ./build/dark-onsen-css-components.css
  ./build/onsen-css-components.css
  ./build/yet-another-onsen-css-components.css

プレビュー画面でも追加したテーマを選択できるようになります。

追加された新しいテーマ

yet-anotherテーマが無事ビルドできることを確認できれば、あとは先程作成したsrc/yet-another-theme.cssを開いてCSS変数を編集することで追加したテーマの色をカスタマイズすることができます。

Modifier

modifier(モディファイアー)は、Onsen UIのコンポーネントにクロスプラットフォーム性とカスタマイズ性を与える独自のHTML属性です。modifierはCSSクラスによって定義されています。Onsen UIでは、modifierを作成してコンポーネントに適用することでコンポーネントのスタイルをカスタマイズすることができます。いくつかのコンポーネントはすぐに使えるプリセットmodifierを持っています。

例えば、以下のボタン群はmodifierを使うことによりそれぞれ別の見た目になっています。なお、動的にmodifierを変更するには、modifier属性をJavaScriptで変更してください。

<ons-button modifier="quiet">Quiet</ons-button>
<ons-button modifier="light">Light</ons-button>
<ons-button modifier="large">Large</ons-button>
<ons-button modifier="cta">Call To Action</ons-button>
<ons-button modifier="material">Material Design</ons-button>

より詳しい情報については、このブログ記事(英語)をご覧ください。

クロスプラットフォームスタイル(オートスタイル)

Onsen UIのコンポーネントは、アプリが動作しているプラットフォームに応じて自動的にスタイルが変化します。この機能はブラウザの開発者ツール(Dev Tools)でiOSとAndroidのビューを切り替えることで簡単にテストできます。もしくは、URLに?platform=ios?platform=androidをクエリ文字列として加えることでもテストできます。

オートスタイルは、ons.platform.isAndroid()trueの時にmodifier="material"をコンポーネントに付加します。オートスタイルは、onsenui.jsの読み込み直後(つまり、アプリの初期化の直前)にons.disableAutoStyling()を実行することで無効にできます。

オートスタイルをより細かく制御できるように、いくつかのツールが提供されています。

プラットフォームユーティリティ

ons.platformオブジェクトを使うと、ons.platform.isIOS()ons.platform.isWebView()などのメソッドが利用できます。

ons.platform.select('android')でプラットフォームをAndroidに固定すると、全てのプラットフォームでマテリアルデザインのコンポーネントを強制的に表示することができます。ただし、このメソッドはアプリが初期化される直前(つまりonsenui.jsを読み込んだ直後)に呼び出す必要があります。

条件要素

ons-ifという名前の条件要素を使うと、プラットフォームや画面の向きに応じて表示するコンテンツを変えることができます。

なお、ReactバインディングとVueバインディングでは<ons-if>コンポーネントは利用できませんので、ons.platform.isIOS()などをご利用ください。

  <ons-if platform="android">
    Androidでのみ表示されるコンテンツ
  </ons-if>
  <ons-if platform="ios other">
    Android以外でのみ表示されるコンテンツ
  </ons-if>

これを使うと、例えば、Androidにだけons-fabを表示したり、iOSにだけボタンを表示したりすることができます。

AngularJS 1バインディングではons-if-platformというディレクティブも提供しています:

<div ons-if-platform="android">
  Androidのみで表示されるコンテンツ
</div>
アイコンショートカット

ons-iconはオートスタイルをより簡単に活用するためのショートカットを提供しています:

<ons-icon icon="ion-navicon, material:md-menu" size="24px, material:20px"></ons-icon>

md-menumaterial modifierが付加されている時のみ表示されます。なお、material以外のmodifierでも同様のことができます。

アニメーション

Onsen UIのルーティングコンポーネント(ナビゲーター、スプリッター、タブバー等)やダイアログには、いくつかのビルトインアニメーションが用意されています。しかし、自分でカスタムアニメーションを作ることもできます。また、ビルトインアニメーションを拡張したり、改造したりすることもできます。しかし、アニメーションの自作や拡張、改造についてはOnsen UIのコアコードに深入りする必要があり、比較的複雑なため注意してください。

Animit

Onsen UIはAnimitという小さなアニメーションライブラリに依存しています。AnimitはモバイルブラウザでのCSSトランジションを制御するライブラリです。

Animitにはons.animitまたはimport { animit } from ons; でアクセスすることができます。Animitは以下のように、CSSアニメーションをキューしたり、ディレイを適用したり、コールバック関数を呼んだりするためのメソッドを提供しています:

let animation1 = animit(myElement) // 与えられた要素に対するアニメーションを定義
  .saveStyle() // 要素が元々持っていたスタイルを保存
  .queue({ // アニメーションの初期状態(位置・スタイル)を設定
    css: {
      transform: 'translate3D(0, 100%, 0)'
    },
    duration: 0
  })
  .wait(0.2) // トランジション開始前にディレイ(遅延)を適用
  .queue({ // アニメーションの次の状態を設定
    css: {
      transform: 'translate3D(0, 0, 0)',
    },
    duration: 0.6,
    timing: 'linear'
  })
  .restoreStyle() // 要素が元々持っていたスタイルを復元
  .queue(done => { // トランジション終了時にコールバック関数を呼ぶ(オプション)
    callback();
    done();
  }
);

animation1.play(); // アニメーションを再生

Animitは要素のstyleプロパティを操作するので、以前のスタイルを失ってしまわないようにするためにsaveStyle()restoreStyle()の2つのメソッドを提供しています。queue({css: {...}, duration: 0, timing: 'linear'})またはqueue({...}, {duration: 0, timing: 'linear'})メソッドはアニメーションのキューにトランジションを追加します。アニメーションを再生すると、まずキューの先頭のトランジションが適用され、その後キューの残りのトランジションが適用されていきます。上述のサンプルコードでは、新しいページを右から左に向かってビュー内に移動させています。translate3d(0, 100%, 0)という位置から始まってtranslate3d(0, 0, 0)という位置に移動しているのはそのためです。wait(...)メソッドはトランジション間のディレイ(遅延)を入れるのに利用できます。最後にqueue(function(done) { ...; done(); })メソッドについてですが、これは必要に応じてコールバック関数を呼び出すのに利用できます。

もし同じアニメーションを複数の要素に適用する必要があるときは、animit([el1, el2]).saveStyle()...のように、animitオブジェクトにHTML要素の配列を渡すことも可能です。

また、2つ以上のアニメーションを同時に再生したい場合は、animation1.play(); animation2.play(); animation3.play();とする代わりにanimit.runAll(animation1, animation2, animation3);メソッドが利用できますので、活用してください。

アニメーターを作成する

アニメーターはOnsen UIが提供しているアニメータークラスを拡張することで一から作成することができます。Onsen UIの各コンポーネントはNavigatorAnimatorAlertDialogAnimatorDialogAnimatorPopoverAnimatorModalAnimatorTabbarAnimatorSplitterAnimatorのようなアニメーターインターフェースを公開(expose)しています。これらを拡張・実装することでアニメーターを作成することができます。もしあなたがOnsen UIを改造したり、Onsen UIのリポジトリにプルリクエストを送ってみたい場合には、この方法でアニメーターを実装するのが最も理想的です。詳しくは、各コンポーネントの既存のアニメーターのソースコードをご覧ください。

アニメーターを作成する際はES2015 (ES6)を利用するのが推奨されますが、特にこだわる必要はありません。ES5でのサンプルコードについてはこちらをご覧ください。

アニメーターを拡張する

新しいアニメーターを作成する方法には、既存のアニメーターを拡張して挙動の一部または全部を修正するという方法もあります。もし、ただ単に既存のアニメーターの見た目やタイミングを少し修正したいだけならこちらの方法の方が簡単です。完全に新しいアニメーターを作る場合でも、こちらの方法の方が簡単です。既存のアニメーターを拡張するには、既存のアニメーターのソースコードのどれかを1つ選んで一通り目を通し、プロパティとメソッドを確認することがまず必要です。アニメーターの具体的な仕様についてですが、どのアニメーターも、新しいアニメーターを返すextend({...})クラスメソッドを提供しています。各コンポーネントの既存のアニメーターはons.elements.Navigator.animatorsons.elements.AlertDialog.animatorsなどの形で公開(expose)されています。これらのオブジェクトはコンポーネントに登録済みの全てのアニメーターを含んでおり、以下のように拡張できます。

var fadeIOS = ons.elements.Navigator.animators['fade-ios'];
var customAnimator = fadeIOS.extend({
  timing: 'cubic-bezier(.1, .7, .1, 1)',
  delay: 0.1,
  push: function(enterPage, leavePage, callback) {
    ons.animit.runAll(
      ons.animit(enterPage)...,
      ons.animit(leavePage)...
    );
  }
});

// 以下の処理は任意です
ons.elements.Navigator.registerAnimator('customAnimationName', customAnimator);

上記のサンプルコードでは、pushアニメーションを上書きしています。popアニメーションは既存のものがそのまま使用されます。 ここで、timingdelayプロパティはpushアニメーションとpopのアニメーションの両方に影響しています。いくつかのアニメーターはbackgroundMaskのような追加プロパティを持っています。使用可能な追加プロパティを確認するには、拡張したいアニメーターのソースコードを確認してください。

新しいアニメーターを作成して登録すると、myNavigator.pushPage('page.html', {animation: 'customAnimationName'})のように、カスタムアニメーションを登録時のアニメーション名だけで簡単に参照できるようになります。<ons-navigator animation="customAnimationName">のように、カスタムアニメーションをナビゲーターのデフォルトのアニメーションにするというようなことも可能です。これは他のコンポーネントについても同様です。