こんにちは、森と申します。

スマートフォン版アメーバピグのWebアプリを担当しています。

スマートフォン版ピグはネイティブアプリとWebアプリがあります。
WebアプリはそのほとんどがHTML5やCSS3を多用していてブラウザで動作します。

JavaScriptやHTML5 APIなどについては、原が以前このブログで書いた
HTML5 Web Applicationのつくりかた」という記事が詳しいので、
この記事ではスマホ版ピグのCSSについてマイページを例にご紹介します。

とても長い記事になってしまいましたが、最後までご覧頂けると嬉しいです。

スクリーンショットで見るCSSプロパティやセレクタ

2012年4月現在、SPピグ内のレイアウトはどのページも大体同じなので、マイページとフォーム要素を抜粋して使っているプロパティやセレクタの中から主要なものをざっと並べてみました。


HTML5やCSS3で追加されたものをあちこちで使っています。
PCサイトを作るとき "IEが対応してないから" と使うのを避けてしまいがちなセレクタも
スマートフォン相手だとあまり気にしなくていいので多用しています。

<img> の zoom:0.5 はRetina Display対策です。
devicePixelRatioが1より大きい機種で見た時ぼやけないように、倍のサイズで作った画像を縮小して表示します。(背景画像はbackground-sizeを使っています)

図には載せませんでしたが、きせかえやショップにあるカルーセルの横移動と、ガチャのアイテムを表示するときの演出はCSS3のアニメーションです。(この記事では触れていません)

CSSで描くグラデーション

ヘッダーとフッターのグラデーションはliner-gradientで描いています。
SPピグでは使っていませんが、円形グラデーションはradial-gradientで作ることができます。

gradientは画像モジュールなので、背景に指定する時はbackground-colorではなくbackground-imageになります。

CSS:background:linear-gradient(top, #535353 0%, #1b1b1b 50%, #000000 51%, #000000 95%);

linear-gradientは先頭(top)がグラデーション開始位置で、色と位置を指定する組み合わせをコンマでつなぐ書き方をします。
将来的にはこの1行だけで良くなると思うのですが、gradientに限らずCSS3のプロパティを使うときはベンダープレフィックスが必要です。
-webkit, -moz, -o, -ms にプレフィックス無しを加えて5種類。毎度書くのは面倒なので
Compassを使ってその手間を省いています。

Sass(Compass CSS3): @include background(linear-gradient(top, #535353 0%, #1b1b1b 50%, #000000 51%, #000000 95%));

横幅を超える長さの文字列を省略する

ピグでは主に長いニックネームを設定している人が対象になるのですが、
マイページのタイトルはサーバーの処理で、
ピグとも、つぶやき、グッピグ帳、おでかけなどではCSSで省略されます。

CSSでの省略は、横幅が定まっているブロック要素に
以下の3つのスタイルを指定することで実現できます。

CSS:overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis;

spanやa要素などに使う場合はdisplay:blockが必要です。(inline-blockは×)

Data属性を使った背景の切り替え

マイページの背景は設定で変更出来ます。
また、PC版と同じように時間によって窓の外の景色が変わります。

次のソースはお部屋の背景を指定している部分を抜粋したものです。
背景の種類時間帯をdata属性で指定しています。

HTML:<div id="room" data-theme="005" data-time="noon" class="myRoom">
CSS:#room[data-theme="005"][data-time="noon"] {
  background-image: url(/img/user/room/bg_005_noon.png);
}

今のところ設定できる背景は6種類。時間帯がそれぞれ3種類なので、
上記のCSSを合計18パターン書く必要があります。
これを手書きするのは骨が折れるので、Sassの@forと@eachで作っています。

Sassのループ処理ソース

data属性だとIDやクラスで使えない値でもそのまま使えるのが嬉しいところです。
(セレクタはかなり冗長になってしまいますが……)

フォーム要素のカスタマイズ

SPピグではデフォルトUIのまま使っているフォーム要素はありません。
最初に全てのスタイルをリセットした上でピグらしいデザインにスタイリングしています。

appearanceはブラウザが提供する標準UIの外観を操作出来るプロパティです。
フォーム要素にappearance:noneを指定するとdivのようにまっさらな状態になりますが
border、background、テキストに関するスタイルなどはリセットされません。

一見ただの画像に見えるマイページの背景選択やショップにあるカルーセルの●はラジオボタンで作られています。
選択時はCSS3で追加された状態疑似クラスの:checkedを使ってスタイルを変えています。

フレキシブルボックスが便利すぎてヤバい

ブラウザの実装具合がまだ揃ってないフレキシブルボックスレイアウトモジュール。
スマートフォン版ピグのブラウザは対象がWebkitなので遠慮なく多用しています。

使い方はとても簡単。
要素をdisplay:boxにするだけです。

フレキシブルボックスの例1:フッター

フッターは右寄せで3つのアイコンが並んでいるだけのものですが、
このデザインになる前は等間隔にアイコンが並んでいました。

フッターのHTMLはリリース当時から変わっていません。
以下は簡略化したソースです。メニューではよくあるコードだと思います。

HTML:<ul>
   <li><a href="/games"><img src="piggGame.png" alt="ピグゲーム"></a></li>
   <li><a href="/"><img src="piggMypage.png" alt="ピグマイページ"></a></li>
   <li><a href="http://ameba.jp/"><img src="amebaMypage.png" alt="マイページ"></a></li>
</ul>

<ul>にdisplay:boxを指定しています。
display:boxで検索をすると段組レイアウトを作るサンプルが上位にヒットしますが、
floatを使っていたものにはほとんど使えると思います。

<li> に指定してあるbox-flexは伸縮比率を指定するプロパティです。
比率の指定なので中に入るテキストや画像の大きさによって微妙にサイズが変わるんですが、
中身の大きさを統一すれば要素が増減しても自動で等間隔になります。

CSS:ul {
   display: -moz-box;
   display: -webkit-box;
   display: -ms-box;
   display: box;}

li {
   display: block;
   text-align: center;
   -moz-box-flex: 1;
   -webkit-box-flex: 1;
   -ms-box-flex: 1;
   box-flex: 1;
}

改修後の右寄せレイアウトは、box-packとbox-flexの値を変えただけです。

CSS:ul{
   -moz-box-pack: end;
   -webkit-box-pack: end;
   -ms-box-pack: end;
   box-pack: end;
}

li {
   -moz-box-flex: 0;
   -webkit-box-flex: 0;
   -ms-box-flex: 0;
   box-flex: 0;
}

フレキシブルボックスの例2:左にサムネイルがあるレイアウト

こういうレイアウトってスマホだとよく目ににするんじゃないかと思います。
SPピグではピグのサムネイルが出るものと、内容を表したアイコンが出るものがあります。
設定ページなどにはテキストの画像だけを使ったリストメニューもあります。

上の画像をよくみると…コンテンツの少ないものが縦方向にセンタリングされていますよね。
テーブルセル以外の要素で縦中央に配置したい時に使える方法って、

  • marginやpaddingで調整
  • display:table-cell; vertical-align:middle
  • height:100px; position:absolute; top:50%; margin-top:-50px
  • 全部画像にする

これくらいでしょうか。
横方向のセンタリングに比べると格段に面倒くさいです。
でもCSS3の box-align なら簡単に揃え位置を変更する事ができます。

以下はサムネイルを表示するレイアウトの図解です。

次のソースは図解部分のHTMLとCSSを簡略化したものです。
テキストのカラーリングは画像とリンクしています。

HTML:<li class="separate">
  <div class="listgroup">
    <a href="javascript:;" class="listinner">
     <div class="thumb pigg">
      <img src="img.png" alt="" class="pigg">
     </div>
    </a>
    <a href="#" class="listinner">
     <div class="spg-listcontent">
     <p class="nickname">いかんせい</p>
     <p class="tweet xsmall">頭痛いと思ってたら腹も痛くなってきた</p>
     <mark class="home">
      <img alt="お部屋へ行く" src="/img/common/icon/home.png">
     </mark>

     </div>
    </a>
  </div>
</li>

ピグのサムネイルを表示しているときのサムネイルとコンテンツの親要素は<a>で、それぞれプロフィールとお部屋にリンクしています。
リンクが2つ並べたいときは<div class="listgroup">を親にしてフレキシブルボックスの対象を<a>タグにしています。

リンク先が1つしかないお知らせやショップ、サムネイルを持たない設定ページのメニューなどでは<li>直下に<a class="listgroup">があります。
box-alignを設定しているので、名前だけを表示する時などはサムネイルの高さに合わせてコンテンツがセンタリングされます。

CSS:li {
  overflow: hidden;
  display: block;
  padding: 5px 5px 6px 5px;
  min-height: 70px;
  background-image: url("data:image/png;base64、~");/* 点線 */
  background-repeat: repeat-x;
  background-position: center bottom;
}

/* li直下の要素 */
.listgroup {
  position: relative;
  width: 100%;
  min-height: 62px;
  padding: 5px;
  display: -moz-box;
  display: -webkit-box;
  display: -ms-box;
  display: box;
  -moz-box-align: center;
  -webkit-box-align: center;
  -ms-box-align: center;
  box-align: center;
  -moz-border-radius: 9px;
  -webkit-border-radius: 9px;
  -o-border-radius: 9px;
  -ms-border-radius: 9px;
  border-radius: 9px;
}

/* サムネイル・コンテンツなどの親要素 */
.listinner {
  -moz-box-flex: 1;
  -webkit-box-flex: 1;
  -ms-box-flex: 1;
  box-flex: 1;
  display: block;
  margin: 0;
  padding: 1px;
}

/* ピグサムネイルの親要素 */
.separate > .listgroup > .listinner:first-child {
  width: 62px;
  -moz-box-flex: 0;
  -webkit-box-flex: 0;
  -ms-box-flex: 0;
  box-flex: 0;
}

listgroupクラス に display-box と box-align:center が設定されています。
box-align:centerはdisplay:boxの対象となる要素の縦揃え位置を指定するプロパティです。

box-alignの対象がインライン要素だと特有の隙間が出来て若干上にズレるので、
問題なければdisplay:blockにしておく方がいいです。

点線は最初倍のサイズの画像を border-image で表示していたのですが、Androidでの表示が汚かったため縮小なしの画像にしてbackground-imageに変えました。
ですがそう変更してもAndroidでは表示位置によって太さが変わって見える事があります。

フレキシブルボックスの仕様が変わりすぎてヤバい…

目が滑る長さのソースとともにフレキシブルボックスを熱く語ってみたのですが……、
W3Cのドラフト上では display:box から display:flexbox に変更されていたりします。

  • display:box → display:flexbox
  • box-align → flex-align
  • box-flex → flex()
  • box-pack → flex-pack

現時点でflexboxの方に対応しているブラウザはないですが、
前に書いたソースで使ったプロパティはもうドラフトにありません……。

なので、ここに書いたソースはブラウザの対応が始まったら陳腐化すると思います。
それがいつなのかはさっぱり分からないですが……フレキシブルボックスを使った覚えがある人は頭の隅に入れておいた方がいいでしょう。

とはいえ、不便だったことが便利になっていくのは喜ばしいことですよね。
仕様変更やブラウザの実装差に振り回されるのは大変ですが、
これからも変化を追い続けて行こうと思います。