第9回 jQuery Mobileのアコーディオンでスマホサイトを制作

前回に続き、jQuery Mobileでカタログサイトを制作します。今回はアコーディオンパネルのCSSを作成します。

アコーディオンパネルのCSS

 アコーディオンパネルのHTMLは次のようなシンプルなものでした(2つ目以降のアコーディオンは省略)。


 <div data-role="collapsible-set">
  <div data-role="collapsible" data-collapsed="true">
   <h3>SITE MENU 1</h3>
   <p>sample text sample text sampletext sample text sample text sample text</p>
   <p>sample text sample text sampletext sample text sample text sample text</p>
  </div>
 (省略)
 </div>

 ところが実際に表示された状態のHTMLをWebインスペクタで見ると、次のように複雑なHTMLに変換されているのが確認できます。


<div data-role="collapsible-set" class="ui-collapsible-set">
  <div data-role="collapsible" data-collapsed="true" class="ui-collapsible-contain">
    <h3 class="ui-collapsible-heading ui-collapsible-heading-collapsed">
      <a href="#" class="ui-collapsible-heading-toggle ui-btn ui-btn-up-z ui-btn-icon-left ui-corner-top" data-theme="z">
        <span class="ui-btn-inner ui-corner-top">
          <span class="ui-btn-text">SITE MENU 1
            <span class="ui-collapsible-heading-status"> click to expand contents</span>
          </span>
          <span data-theme="d" class="ui-btn ui-btn-up-d ui-btn-icon-left ui-btn-corner-all ui-shadow">
            <span class="ui-btn-inner ui-btn-corner-all ui-corner-top">
              <span class="ui-btn-text"></span>
              <span class="ui-icon ui-icon-plus ui-icon-shadow"></span>
            </span>
          </span>
        </span>
      </a>
    </h3>
    <div class="ui-collapsible-content ui-collapsible-content-collapsed" aria-hidden="true">
      <p>sample text sample text sampletext sample text sample text sample text</p>
      <p>sample text sample text sampletext sample text sample text sample text</p>
    </div>
  </div>
  (省略)
</div>

 元のHTMLと比べると複雑なので分かりづらいですが、大まかには次の図のような構造になっています。

アコーディオンパネルの構造

 見出しとなっているラベル部分、コンテンツが隠れているパネル部分、ラベルの左側にあるアイコン部分に分けてCSSを設定してきましょう。

アコーディオンのラベル部分のCSS

 ラベル部分のCSSは以下のようになります。


.ui-body-z .ui-collapsible-set{
  margin-top:20px;
}
.ui-body-z .ui-collapsible-contain{    ……【7】
  margin-top:-5px;
}
.ui-body-z .ui-collapsible-contain h3{
  border-radius:8px 8px 0 0;
  margin:0 8px;
  font-weight:normal;
}
.ui-body-z .ui-collapsible-contain:last-of-type h3{
  border-radius:8px;
}
.ui-body-z .ui-collapsible-contain:nth-of-type(1) h3{    ……【8】
  background:#95be66;
  background: -webkit-gradient(linear, left top, left bottom,from(#95be66),to(#649f1f));
}
.ui-body-z .ui-collapsible-contain:nth-of-type(1) h3:not(.ui-collapsible-heading-collapsed){    ……【9】
  border-bottom:4px #95be66 solid;
}
.ui-body-z .ui-collapsible-contain:nth-of-type(2) h3{    ……【8】
  background:#b0ba63;
  background: -webkit-gradient(linear, left top, left bottom,from(#b0ba63),to(#8c9a1b));
}
.ui-body-z .ui-collapsible-contain:nth-of-type(2) h3:not(.ui-collapsible-heading-collapsed){    ……【9】
  border-bottom:4px #b0ba63 solid;
}
.ui-body-z .ui-collapsible-contain:nth-of-type(3) h3{    ……【8】
  background:#bfa65c;
  background: -webkit-gradient(linear, left top, left bottom,from(#bfa65c),to(#a07d10));
}
.ui-body-z .ui-collapsible-contain:nth-of-type(3) h3:not(.ui-collapsible-heading-collapsed){    ……【9】
  border-bottom:4px #bfa65c solid;
}
.ui-body-z .ui-collapsible-contain:nth-of-type(4) h3{    ……【8】
  background:#bf8a5c;
  background: -webkit-gradient(linear, left top, left bottom,from(#bf8a5c),to(#a15411));
}
.ui-body-z .ui-collapsible-contain:nth-of-type(4) h3:not(.ui-collapsible-heading-collapsed){    ……【9】
  border-radius:8px 8px 0 0;
  border-bottom:4px #bf8a5c solid;
}
.ui-body-z .ui-collapsible-contain a{
  font-size:14px;
  color:white;
  text-shadow:1px 0 1px rgba(0,0,0,0.3); 
  text-decoration:none;
  padding:8px 0 10px;
}
.ui-body-z .ui-collapsible-contain:last-of-type a{
  padding-bottom:8px;
}

 アコーディオンパネルのラベル部分は以下の図のような構造になっていて、パネルが閉じているときはラベル同士が少し重なっています。

 【7】ではパネル全体を5px上にずらすことで、下のラベルが上のラベルに重なるように設定しています。

 ラベル部分のグラデーションは【8】で設定しています。グレースフルデグラデーション(関連記事)の考え方に基づき、-webkit-gradientに対応しているデバイスにのみグラデーションを適用し、対応していないブラウザーにはbackgroundで設定した背景色が適用されるように設定しています。

 多くのブラウザーやデバイスでグラデーションを表現しようとするとコード量が膨大になりますが、現在発売されているiPhoneやAndroidの標準ブラウザーへの対応ならこれで十分です。CSS3のnth-of-type擬似クラスを利用して、行ごとのグラデーションカラーを設定します。

 【9】では、パネルが開いているときのラベルのスタイルを設定しています。jQuery Mobileでは、アコーディオンパネルが閉じていると、h3要素にclass属性「ui-collapsible-heading-collapsed」が自動的に追加されます。セレクターで h3:not(.ui-collapsible-heading-collapsed) とすると、パネルが閉じていないとき(つまりパネルが開いているとき)のスタイルを設定できます。サンプルでは、4pxのボーダーをボックスの下に設定しています。

アコーディオンのパネル部分のCSS

 パネル部分には次のようなCSSを設定します。


.ui-body-z .ui-collapsible-contain .ui-collapsible-content{
  background-color:#edf3e4;
  margin:0 8px;
  padding:8px;
  border-left: 1px solid #ccc49a;
  border-right: 1px solid #ccc49a;
  -webkit-box-shadow: 0 0 10px #c7ad77 inset;    ……【10】
  box-shadow: 0 0 10px #c7ad77 inset;    ……【10】
}
.ui-body-z .ui-collapsible-contain .ui-collapsible-content p{
  margin:5px;
  color:#665400;
  font-size:12px;
}
.ui-body-z .ui-collapsible-contain:last-of-type .ui-collapsible-content{
  border-bottom: 1px solid #ccc49a;
  border-radius: 0 0 8px 8px;    ……【11】
}

 【10】ではCSS3のbox-shadowプロパティを使ってボックスの内側に影を付けています。box-shadowプロパティの値にinsetを指定すると、ボックスの内側に影を設定でき、ボーダーよりも淡いふちを表現したいときに利用できます。

内側にbox-shadowを適用して影を表現している

 【11】は最後のパネルの処理です。最後のパネルだけ、ボックスの下部分を角丸にしています。border-radiusプロパティは、値が1つのときはすべての角の半径をまとめて、値が2つの場合は左上・右下と右上・左下の半径、値が3つの場合は左上と右上・左下の半径、値が4つの場合は左上と右上と右下と左下の半径が個別に設定できます。実際にはすべての値をまとめて設定するか、個別に設定することが多いでしょうが、覚えておくと便利です。

アコーディオンのアイコン部分のCSS

 アコーディオンパネルの最後は、アイコン部分のCSSです。


.ui-body-z .ui-collapsible-heading a span.ui-btn {    ……【12】
  width:15px;
  height:15px;
}
.ui-body-z .ui-collapsible-contain .ui-icon{    ……【13】
  background:url("./images/icon-check.png") no-repeat 0 5px;
  -webkit-background-size:13px 7px;
  background-size:13px 7px;
  -webkit-box-shadow:none;
  box-shadow:none;
  width:15px;
  height:15px;
}
.ui-body-z .ui-collapsible-contain .ui-btn-hover-d{    ……【14】
  border: 3px solid #e6edc5;
  background:rgba(255,255,255,.5)
}
.ui-body-z .ui-collapsible-contain .ui-btn-up-d {    ……【14】
  border: 3px solid #e6edc5;
  background: #5f9c17;
}
.ui-body-z .ui-collapsible-contain:nth-of-type(2) .ui-btn-up-d {    ……【14】
  background: #849212;
}
.ui-body-z .ui-collapsible-contain:nth-of-type(3) .ui-btn-up-d {    ……【14】
  background: #9a780f;
}
.ui-body-z .ui-collapsible-contain:nth-of-type(4) .ui-btn-up-d {    ……【14】
  background: #a15411;
}

 .ui-collapsible-heading a span.ui-btn や .ui-collapsible-contain .ui-iconにはデフォルトのアイコンの設定があります。以下の図で比較してみると、今回作成するサンプルサイトのデザインと共通性があるのが分かります。

 そこで、デフォルトのスタイルを部分的に上書きして新しいアイコンを設定します。【12】では、アイコンのサイズを15×15pxに設定。【13】では、アイコンの背景をチェックマークの画像に変更しています。

 アイコンの周りの丸は、border-radiusプロパティを使って表現しています。jQuery Mobileのデフォルトでは以下のように設定されていますので、【14】でボーダーの太さや色だけを上書きします。


.ui-btn-corner-all {
  border-radius: 1em 1em 1em 1em;
}

 なお、タッチパネルのスマートフォンでは確認できませんが、jQuery Mobileではマウスオーバー時のスタイルも定義されているので、【14】のように設定しておくとよいでしょう。ui-btn-hover-dがマウスオーバー時、ui-btn-up-dが通常時のスタイルです。

フッターのCSS

 アコーディオン部分が終わったら、コンテンツ領域のCSSは完成です。次に、フッターのCSSを設定します。フッターのHTMLは次のように変更されています。


<div data-role="footer" data-theme="z">
 <small>Copyright &copy; 2011 ASCII MEDIA WORKS. All rights reserved.</small>
</div>

 ↓


<div data-role="footer" data-theme="z" class="ui-footer ui-bar-z" role="contentinfo">
  <small>Copyright © 2011 ASCII MEDIA WORKS. All rights reserved.</small>
</div>

 上のHTMLに対して次のようなスタイルを適用します。


/*
.footer
-------------------*/
.ui-body-z .ui-footer{
  background-image:url("./images/footer-background.jpg");
  background-size:100% 64px;
  height:64px;
}
.ui-body-z .ui-footer small{
  margin-top:40px;
  font-size:10px;
  color:#504510;
  text-align:center;
  display:block;
}
.ui-body-z .ui-footer small:before{
  content:url("./images/footer-reef.png");
  padding-right:1em;
}

 基本的なCSSなので特に難しい点はないでしょう。背景画像はヘッダーと同じようにbackground-sizeを利用してデバイスの横幅にフィットさせています。

フッターのデザイン

詳細ページのモーダルウィンドウ

 最後に、詳細ページで画像をタップすると表示されるモーダルウィンドウです。モーダル部分のHTMLは次のようになっています。


<div data-role="page" id="img" class="modal" data-theme="z">
 <a href="#detail" data-rel="back"><img src="./images/image01.jpg" alt=""></a>
</div>

 ↓


<div data-role="dialog" id="img" class="modal ui-page ui-body-z ui-dialog ui-page-active" data-theme="z" data-url="img" tabindex="0" role="dialog" style="min-height: 821px; ">
  <a href="" class="ui-link" data-transition="pop" data-direction="reverse"><img src="./images/image01.jpg" alt=""></a>
</div>

 これに対して次のようなCSSを適用します。


/*
.modal
-------------------*/
.ui-body-z.modal{
  background-image:url("./images/background.jpg");
}
.ui-body-z.modal a{
  position:absolute;
  left:50%;
  top:50%;
}
.ui-body-z.modal a img{
  margin-top:-50%;
  margin-left:-50%;
  max-width:100%;
  max-height:100%;
}

 a要素に対してposition:absoluteのletf:50%とtop:50%、img要素に対してmargin-top:-50%とmargin-left:-50%を指定することで画像を中央に表示しています。また、画像がウィンドウからはみ出さないように、max-width:100%とmax-height:100%をそれぞれ指定しています。

<画像>08.jpg
画像をタップするとモーダルウィンドウで拡大した画像が表示される

 以上で、サンプルサイトが完成しました。完成したサイトは以下から閲覧できます。

 CSSを高度にカスタイズすることで、jQuery Mobileでも独自デザインのスマートフォンサイトを制作できます。

実務ではまる落とし穴:

iPhoneで横向きにすると拡大される!

 サンプルサイトをiPhoneで開き、端末をlandscapeモード(横向き)にすると、ページが拡大されて表示されます。

 この問題はiPhoneの仕様で、meta要素のviewportを次のように変更すると問題を回避できます。


<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1">

 これでlandscapeモードでも拡大されず、画面幅にぴったりフィットして表示されます(サンプル3)。

<画像>10.jpg
viewportを変更してlnadscapeで確認した状態

 ただし、viewportに「maximum-scale=1」を指定すると、ピンチイン/ピンチアウト操作によるページの拡大・縮小ができなくなるデメリットがあります。事前にどちらを優先するか決めておく必要があるでしょう。


Comments