Lab

by engineering@dwango.jp

CSSを追加してjQuery Mobileのデザインをカスタマイズ!

こんにちは初めまして、石崎と申します。 今回は jQuery Mobile シリーズ3回目!ということで、jQuery Mobile デザイン編です!

jQuery Mobile には 標準のテーマ(色見本)が5つ用意されています。この標準のテーマを使用してアプリを作ることも可能です。しかし、アプリやサイトにはそれぞれのデザインやブランドイメージがあり、標準のテーマとは違うイメージのものを作りたい場合があります。

そんな時のために、今回は CSS などをカスタマイズして独自のデザインをいれていくノウハウについて説明します。

対象読者

  • CSS3, HTML5 の知識がある方

jQuery Mobile の仕組み

今回は jQuery Mobile のバージョン 1.0 RC2 を扱います。

先ほど述べたように、jQuery Mobile には標準のテーマが5つ用意されていますdata-themeというカスタム属性の値に a~e を設定することによって、色見本 a~e が実行されます。各要素ごとにテーマを変更することも可能です。新しくテーマを作りたい場合は「f~z」を使用します。

テーマ以外にも、見た目や振る舞いを指定する data-* というカスタム属性が多数用意されています。

それら data-* に応じて jQuery Mobile が HTML を書き換え、class を追記し、スタイルのついた実際に表示される画面を生成しているのです。つまり「マークアップするHTML」と「表示されるHTMLコード」は異なるものになります。

図

スタイルが自動的に適用されるので大変便利ではありますが、「マークアップするHTML」に記載してない class がたくさん書き出されるので、デザインをカスタマイズする際には注意が必要です。

今回は「マークアップするHTML」と「表示されるHTMLコード」、以上の2つについて解説していきます。

マークアップするHTML

前々回の「jQuery Mobileの紹介」では「data-role属性の一部」を紹介しました。今回はよく使われるコンポーネントとそのオプションをピックアップして紹介します。

div data-role=”page”

1つのページとして扱う領域(公式サンプル

要素 説明
data-theme="[a-z]" テーマ。a~eが用意されている。
(デフォルトではc)
data-fullscreen="true" フルスクリーン表示

div data-role=”header”

ページのヘッダ領域(公式サンプル

要素 説明
data-theme="[a-z]" テーマ。a~eが用意されている。
(デフォルトではa)
data-position="fixed" 画面上部に固定表示
data-add-back-btn="true" 前画面がある場合は左端に「Back」ボタン追加
data-back-btn-text="戻る" 「Back」ボタンのテキスト「Back」を「戻る」に変更
ヘッダ内の要素 説明
a href="#" data-icon="[アイコン種類]" アイコン付ボタン設置
class="ui-btn-right" ボタンの位置を右端に

div data-role=”footer”

ページのフッタ領域(公式サンプル

要素 説明
data-theme="[a-z]" テーマ。a~eが用意されている。
(デフォルトではa)
data-position="fixed" 画面下部に固定表示
data-id="***" 別pageのfooterにも同じ値を設定すると
ページ移動してもアンカー保持できる
フッタ内の要素 説明
a href="#" data-role="button" data-icon="[アイコン種類]" アイコン付ボタン設置
div data-role="controlgroup" data-type="horizontal" 複数のボタンをグループ化

data-role=”content”

ページのコンテンツ領域(公式サンプル

要素 説明
data-theme="[a-z]" テーマ。a~eが用意されている。
(デフォルトではc)

class=”ui-grid-[a/b/c/d]”

複数カラム(公式サンプル

要素 説明
data-theme="[a-z]" テーマ。a~eが用意されている。
div class="ui-grid-a" 2カラム
div class="ui-grid-b" 3カラム
div class="ui-grid-c" 4カラム
div class="ui-grid-d" 5カラム
class="ui-grid-[a/b/c/d]"内の要素 説明
div class="ui-block-a" 一番左のカラム
div class="ui-block-b" 左から2番目のカラム
div class="ui-block-c" 左から3番目のカラム
div class="ui-block-d" 左から4番目のカラム
div class="ui-block-e" 左から5番目のカラム

data-role=”collapsible”

折り畳みコンテンツ(公式サンプル

要素 説明
data-theme="[a-z]" 上部分のテーマ。
a~eが用意されている。
data-content-theme="[a-z]" 折りたたまれたコンテンツ内のテーマ。
a~eが用意されている。
data-collapsed="false" 画面を読み込んだ時に
折りたたまれたコンテンツを展開する。
collapsibleの外側の要素 説明
data-role="collapsible-set" グループ化された見た目にする

ul/ol data-role=”listview”

リスト(公式サンプル

要素 説明
data-theme="[a-z]" テーマ。a~eが用意されている。
data-inset="true" 余白のある角丸リスト
data-split-icon="[アイコン種類]" 分割されたリストのアイコン種類を設定
liタグの中にaタグを2つ設定する
data-split-theme="[a-z]" 分割されたリストのアイコン色見本を設定
data-filter="true" 検索フォームの設置
listview内の要素 説明
li data-role="list-divider" リスト内の見出し
span class="ui-li-count" 右側にカウント数
span class="ui-li-aside" 右側にテキスト
img 左側にサムネイル画像(80px)
img class="ui-li-icon" 左側にサムネイル画像(16px)

div data-role=”navbar”

ナビゲーションバー(公式サンプル

要素 説明
data-theme="[a-z]" テーマ。a~eが用意されている。
data-iconpos="[位置]" アイコンの位置
bottom / left / right
div data-role="navbar"内の要素 説明
a href="#" class="ui-btn-active" 選択状態のリンク
a href="#" data-icon="[アイコン種類]" アイコンの種類
data-theme="[a-z]" aliにテーマを指定

data-role=”fieldcontain”

フォーム要素(公式サンプル

要素 説明
data-theme="[a-z]" テーマ。a~eが用意されている。
data-role="fieldcontain"内の要素 説明
input type="search" 検索フォーム。
虫眼鏡マークのアイコンがつく。
input type="range" スライダー。
value(初期値)、min(最小値)、max(最大値)の設定も行う。
input data-track-theme="[a-z]" スライダーのトラック部分にテーマを指定
select data-role="slider" スイッチ
fieldset data-role="controlgroup" radiocheckboxselect
グループ化(縦)
fieldset data-role="controlgroup" data-type="horizontal" radiocheckboxselect
グループ化(横)
data-theme="[a-z]" 各フォーム要素にテーマ設定

ボタン要素

リンクとフォームの2種類(公式サンプル

ボタンの種類 説明
a href="#" data-role="button リンクボタン
button フォームボタン
Input type="button / submit / reset / image"
要素 説明
data-theme="[a-z]" テーマ。a~eが用意されている。
data-inline="true" ボタンの横幅を縮小
data-icon="[アイコン種類]" アイコンの種類を指定
data-iconpos="right / top / bottom" アイコンの位置を指定
data-iconpos="notext" テキストを非表示にしアイコンのみ表示
ボタンの外側の要素 説明
div data-role="controlgroup" グループ化(縦)
div data-role="controlgroup" data-type="horizontal" グループ化(横)

アイコンの種類

data-icon="***"data-split-icon="***" で指定(公式サンプル

説明
arrow-l 左矢印
arrow-r 右矢印
arrow-u 上矢印
arrow-d 下矢印
delete バツ
plus プラス
minus マイナス
check レ点
gear ギア
refresh 更新
forward 前方へ
back 戻る
grid グリッド
star
alert アラート
info
home
search 虫眼鏡

以上、代表的なものを紹介しました。 これらを使ってUIを組み立てていきます。

表示されるHTMLコード

では実際にどんなclassに書き換えられているのでしょう? chromeやsafariの開発ツールで見くらべてみると、よく分かります。

図

ここでは「themeに関するclass」と「theme以外のclass」とで分けて、代表的な class を紹介します。CSS作成の参考にしてください。

themeに関するclass

主に背景色や文字色など、色の指定です。 data-theme="[a-z]"を指定することによってclassは以下のように書き加えられます。

class data-themeを設定した個所
.ui-body-[a-z] data-role="page"部分
data-role="collapsible"部分
.ui-bar-[a-z] data-role="header"部分
data-role="footer"部分
.ui-btn-up-[a-z]
.ui-btn-down-[a-z]
.ui-btn-hover-[a-z]
ボタン部分

theme以外のclass

レイアウトや形状の指定が主です。

class 説明
.ui-body ページ 領域
.ui-header ヘッダ
.ui-footer フッタ
.ui-field-contain フォーム
.ui-listview リスト
.ui-btn-active 選択されたボタン ボタン部分
.ui-btn-corner-** 角丸ボタン(**は角丸の個所)
.ui-corner-** 角丸グループ(**は角丸の個所) グループ
listやradioなど
.ui-icon-[アイコン種類] アイコンの種類 アイコン
.ui-input-search 検索 フォーム要素

角丸は

  • ui-corner-tl:左上が角丸
  • ui-corner-top:上が角丸
  • ui-corner-left:左が角丸
  • ui-corner-all:全ての四隅が角丸

…といったルールでclass名が付けられています。

実装

前回前々回の記事でデモとして作成したTumblrの投稿を取得するアプリに、デザインをいれてみましょう!

準備

デザインイメージを用意します。 今回は、Tumblrの公式サイトのイメージでいきます。

テーマを割り当てるアルファベットを決めます。 「a~e」は標準で設定されているので、それ以外を設定しましょう。 今回はTumblrの頭文字「t」で設定することにします。

HTMLの各所にdata-theme="t"を設定します。 スタイルシートは「theme_t.css」を新規作成し、外部でもつことにします。

検索画面のマークアップ

画面イメージ

フォーム要素(inputbutton)は、それぞれをdiv data-role="fieldcontain"で囲みましょう。そうすることで、どんな画面サイズでも整形された状態で表示されます。

data-theme="t"は、デフォルトでテーマが設定されている個所に設定すると良いでしょう。

<div data-role="page" id="search" data-theme="t"><!-- ←テーマ設定 -->
    <div data-role="header" data-theme="t"><!-- ←テーマ設定 -->
        <h1>Tumblr投稿閲覧</h1>
    </div>
    <div data-role="content">
        <div data-role="fieldcontain">
            <label for="user-id">ユーザーを検索</label>
            <input type="search" name="search" id="user-id">
        </div>
        <div data-role="fieldcontain">
            <button data-theme="t">検索</button><!-- ←テーマ設定 -->
        </div>
    </div>
</div>

CSSは、基本的にui-body-tを起点に設定していきます。そうすることによって他のテーマのCSSに干渉しないようにします。

変更箇所は以下の通りです。

  • headerの色
  • content(body)の色
  • フォーム要素の色、スタイル
.ui-body-t { background:#2c4762 }
.ui-body-t .ui-bar-t.ui-header {
    background:#1c3146;
    color:#96a4b1;
    border-bottom:1px solid #000102;
    background-image: -webkit-gradient(linear, left top, left bottom, from(#1c3146), to(#10253a));
    background-image: -webkit-linear-gradient(top, #1c3146, #10253a);
    background-image:    -moz-linear-gradient(top, #1c3146, #10253a);
    background-image:     -ms-linear-gradient(top, #1c3146, #10253a);
    background-image:      -o-linear-gradient(top, #1c3146, #10253a);
    background-image:         linear-gradient(top, #1c3146, #10253a);
}
.ui-body-t .ui-input-search { background:#faffbd; }
.ui-body-t label { color:#FFFFFF; }
.ui-body-t .ui-input-clear.ui-btn-up-t { background: #ccc }
.ui-body-t .ui-br { border:none; }

#search.ui-body-t .ui-field-contain:nth-child(2) { padding-top:0; }
.ui-btn-up-t,
.ui-btn-hover-t,
.ui-btn-down-t {
    -moz-box-shadow:0 1px 0 rgba(255,255,255,0.2), 0 1px 2px rgba(255,255,255,0.7) inset;
    -webkit-box-shadow:0 1px 0 rgba(255,255,255,0.2), 0 1px 2px rgba(255,255,255,0.7) inset;
    box-shadow:0 1px 0 rgba(255,255,255,0.2), 0 1px 2px rgba(255,255,255,0.7) inset;
    border:1px solid #2a3f56; 
    background: #8bad68 ;
    font-weight: bold;
    color:rgba(0,0,0,0.63);
    text-shadow:0 1px 1px rgba(255,255,255,0.37);
    background-image: -webkit-gradient(linear, left top, left bottom, from(#94b772), to(#769659));
    background-image: -webkit-linear-gradient(top, #94b772, #769659);
    background-image:    -moz-linear-gradient(top, #94b772, #769659);
    background-image:     -ms-linear-gradient(top, #94b772, #769659);
    background-image:      -o-linear-gradient(top, #94b772, #769659);
    background-image:         linear-gradient(top, #94b772, #769659);
}
.ui-btn-up-t { opacity:.9; }
.ui-btn-hover-t { opacity:1 }
.ui-btn-down-t {
    -moz-box-shadow:0 1px 0 rgba(255,255,255,0.3), 0 1px 3px rgba(0,0,0,0.7) inset;
    -webkit-box-shadow:0 1px 0 rgba(255,255,255,0.3), 0 1px 3px rgba(0,0,0,0.7) inset;
    box-shadow:0 1px 0 rgba(255,255,255,0.3), 0 1px 3px rgba(0,0,0,0.7) inset;
    opacity:1;
}
.ui-btn-up-t a.ui-link-inherit { color: #fff; }

検索結果のマークアップ

画面イメージ

こちらも同じようにdata-theme="t"を設定していきます。

<div data-role="page" id="result" data-add-back-btn="true" data-back-btn-text="戻る" data-theme="t"><!-- ←テーマ設定 -->
    <div data-role="header" data-theme="t"><!-- ←テーマ設定 -->
        <h1>[<span class="user-id"></span>] の投稿</h1>
    </div>
    <div data-role="content">
        <ul data-role="listview" id="post-list" data-inset="true" data-theme="t"><!-- ←テーマ設定 -->
        </ul>
    </div>
</div>

続いてCSSです。 変更箇所は以下の通りです。

  • headerのボタンの色
  • 検索結果listのリンクの色

同じように.ui-body-tを起点にして設定していきます。 ヘッダーのボタンは.ui-header .ui-btn-up-t、 リストのボタンは.ui-listview .ui-btn-up-tと設定すると良いでしょう。

/*結果-header*/
.ui-body-t .user-id { color:#fff;}
#result.ui-body-t .ui-header .ui-btn-up-t,
#result.ui-body-t .ui-header .ui-btn-hover-t,
#result.ui-body-t .ui-header .ui-btn-down-t {
    -moz-box-shadow:0 1px 0 rgba(255,255,255,0.2), 0 1px 2px rgba(255,255,255,0.7) inset;
    -webkit-box-shadow:0 1px 0 rgba(255,255,255,0.2), 0 1px 2px rgba(255,255,255,0.7) inset;
    box-shadow:0 1px 0 rgba(255,255,255,0.2), 0 1px 2px rgba(255,255,255,0.7) inset;
    border:1px solid #2a3f56; 
    background: #8bad68 ;
    font-weight: bold;
    color:rgba(0,0,0,0.63);
    text-shadow:0 1px 1px rgba(255,255,255,0.37);
    background-image: -webkit-gradient(linear, left top, left bottom, from(#94b772), to(#769659));
    background-image: -webkit-linear-gradient(top, #94b772, #769659);
    background-image:    -moz-linear-gradient(top, #94b772, #769659);
    background-image:     -ms-linear-gradient(top, #94b772, #769659);
    background-image:      -o-linear-gradient(top, #94b772, #769659);
    background-image:         linear-gradient(top, #94b772, #769659);
}
#result.ui-body-t .ui-header .ui-btn-up-t { opacity:.9; }
#result.ui-body-t .ui-header .ui-btn-hover-t { opacity:1 }
#result.ui-body-t .ui-header .ui-btn-down-t {
    -moz-box-shadow:0 1px 0 rgba(255,255,255,0.3), 0 1px 3px rgba(0,0,0,0.7) inset;
    -webkit-box-shadow:0 1px 0 rgba(255,255,255,0.3), 0 1px 3px rgba(0,0,0,0.7) inset;
    box-shadow:0 1px 0 rgba(255,255,255,0.3), 0 1px 3px rgba(0,0,0,0.7) inset;
    opacity:1;
}

/*結果-listview*/
#result.ui-body-t .ui-listview .ui-btn-up-t {
    border: 1px solid #ccc;
    background: #eee;
    font-weight: bold;
    color: #444 ;
    text-shadow: 0 1px 1px #f6f6f6;
    background-image: -webkit-gradient(linear, left top, left bottom, from(#fdfdfd ), to(#eee));
    background-image: -webkit-linear-gradient(top, #fdfdfd , #eee);
    background-image:    -moz-linear-gradient(top, #fdfdfd , #eee);
    background-image:     -ms-linear-gradient(top, #fdfdfd , #eee);
    background-image:      -o-linear-gradient(top, #fdfdfd , #eee);
    background-image:         linear-gradient(top, #fdfdfd , #eee);
}

#result.ui-body-t .ui-listview .ui-btn-up-t a.ui-link-inherit {
    color: #2F3E46 ;
}

#result.ui-body-t .ui-listview .ui-btn-hover-t {
    border: 1px solid #bbbbbb;
    background: #dadada ;
    font-weight: bold;
    color: #101010 ;
    text-shadow: 0 1px 1px #fff ;
    background-image: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#dadada ));
    background-image: -webkit-linear-gradient(top, #ededed , #dadada);
    background-image:    -moz-linear-gradient(top, #ededed , #dadada);
    background-image:     -ms-linear-gradient(top, #ededed , #dadada);
    background-image:      -o-linear-gradient(top, #ededed , #dadada);
    background-image:         linear-gradient(top, #ededed , #dadada);
}
#result.ui-body-t .ui-listview .ui-btn-hover-t a.ui-link-inherit {
    color: #2F3E46;
}
#result.ui-body-t .ui-listview .ui-btn-down-t {
    border: 1px solid #808080 ;
    background: #fdfdfd ;
    font-weight: bold;
    color: #111111 ;
    text-shadow: 0 1px 1px  #ffffff ;
    background-image: -webkit-gradient(linear, left top, left bottom, from(#eee ), to(#fdfdfd ));
    background-image: -webkit-linear-gradient(top, #eee , #fdfdfd);
    background-image:    -moz-linear-gradient(top, #eee , #fdfdfd);
    background-image:     -ms-linear-gradient(top, #eee , #fdfdfd);
    background-image:      -o-linear-gradient(top, #eee , #fdfdfd);
    background-image:         linear-gradient(top, #eee , #fdfdfd);
}
#result.ui-body-t .ui-listview .ui-btn-down-t a.ui-link-inherit {
    color: #2F3E46 ;
}

出来上がったページはこちらです! デモページ

デザインをいれると更にアプリらしくなりますね。

まとめ

先日、jQuery MobileのテーマCSSを新しく生成することができるTheme Roller正式版がリリースされました。(リリース記事はこちらです。

Theme Rollerも使いつつ、この記事で解説したclassのカスタマイズも行い、独自のデザインを設定して、ブランドイメージを守った更にクオリティの高いものを作っていきましょう!