iOS5のMobile Safariから使えるようになったHTML5・CSSを試してみました【後編】


前編ではiOS5のMobile Safariから使えるようになったHTMLやCSSの要素などについて試してみた、半分だけ紹介・解説しました。まだ前編を読んでいないという方は先に前編を読んでおくことをおすすめします。
→iOS5のMobile Safariから使えるようになったHTML5・CSSを試してみました【前編】


ざっと今回試してみたプロパティやテクニックをもう一度振り返っておくと以下のような感じです。

  • position:fixedを使ったタブUI
  • overflow:scrollを1本指ですいすいスクロールさせる
  • Web Symbols typeface
  • CSS Only Transition Effects
  • 新しいInput typeとネイティブっぽいselect UI
  • Inline SVGとSVG icons


前編では最初の3つを紹介・解説したので、後編では残りの3つを紹介したいと思います。
と思いましたが、今回紹介するものもデモ自体はすでにネタばれしているのでつまらないなぁと思いました。そこで、いろいろと考えたのですが、もう一つネタになりそうなのをiOS5からサポートしていたのでそれを新たに追加しました!
それは、「writing-modeプロパティ」と「ヒラギノ明朝」です。つまりどういう事かというと縦書きで小説っぽい見た目ができるということです。というわけで今回は「縦書きの読みもの表現」を加えた4つのテーマについて解説します。


 ↓今回、紹介するもの

  • CSS Only Transition Effects
  • 新しいInput typeとネイティブっぽいselect UI
  • Inline SVGとSVG icons
  • 縦書きの読みもの表現


 ↓今回もサンプルのリンク載せときます
→iOS5 WebApp Demo : Overview of new things supported in iOS5 Safari

CSS Only Transition Effects

まずはTransition Effectの解説です。Transition Effectは結構前からいろいろと試したりしていました。
例えば、1年以上前に作ったCSS3によるTransition Effects 30では-webkit-animationや-webkit-transformを使って30種類のスライドショー・トランジション・エフェクトを作成して紹介しました。
このころ僕の持っていたデバイスはiPhone 3GでOSもiPhoneOS 3で、これだけのグラフィックをMobile Safariで動かすのは難しかったです(なんとなく動きますがガタガタみたいな)。ただ、CSS3のanimationやtransformの勉強にはけっこうなったかなと思います。


CSS3によるTransition Effects 30ではトランジションのきっかけとなるクリックなどのイベントをすべてJavascriptで制御していました。
しかし、最近ブログに書いたCSS3だけで作るClickableなUIでは、そういったクリックイベントなどもJavascriptを使わずにCSSのみで処理するテクニックを紹介しています。
CSSのみでイベントを制御する方法をこのエントリーでは2種類紹介しています。一つは「:checked」擬似セレクタとInput要素、間接セレクタを使ったもので、もう一つは「:target」擬似セレクタを使ったものです。
今回のiOS5 WebApp Demoでは前者のほうを用いていて、前編でもFooter Tab UIのところで紹介しました。Footer Tab UI意外にもほとんどのパーツでコレを使用しています。



というわけで、CSS3によるTransition Effects 30CSS3だけで作るClickableなUIを踏まえた上で今回のiOSネイティブアプリ風Transition Effectsを作っています。
「:checked」擬似セレクタと間接セレクタの辺りが分かっていれば仕組みはとても簡単です。HTMLとCSSを簡単に解説すると以下のような感じです。

<input tyep="checkbox" id="slide">
<div class="page" id="page1">
  <label for="slide" onclick="">Next Page</label>
</div>
<div class="page" id="page2">
  <label for="slide" onclick="">Back Page</label>
</div>
input {
  display:none;
}
.page {
  position:absolute;
  width:100%;
  height:100%;
  -webkit-transition:0.5s;
}
#page2 {/* page2は右にずらしておく */
  -webkit-transform:translateX(100%);
}
input:checked ~ #page1 {/* input要素にチェックが入ったら左にずらす */
  -webkit-transform:translateX(-100%);
}
input:checked ~ #page2 {
  -webkit-transform:translateX(0%);
}

非常にシンプルです。実は最近まで、Webkit系ブラウザでの間接セレクタの振る舞いが上手く動いていなかったのですが、バージョンアップしてChromeやSafariでもちゃんと動くようになりました(やったー。Firefoxでは前からちゃんと動いていました)。
iOSのMobile Safariも例外ではなく、最近まで間接セレクタが上手く使えてなかったのですがiOS5から使えるようになったみたいです。便利ですね!
上記に示した例は横にスライドするだけの簡単なトランジションですが、アニメーションを凝ったものにすればいろいろな表現ができると思います。


今回もシンプルに実装したDemoも用意しました。
→ Simple Slide Transition

新しいInput typeとネイティブっぽいselect UI

iOS5のMobile Safariから新たにInput要素のタイプ属性のサポートが追加されています。具体的には、Date, Datetime, Month, Timeなどの日付入力用Input typeで、タップするとホイールセレクタUIで日付を選択できるようになりました。
今回のサンプルではそれ以外にも元々サポートしていたnumberやpasswordといったtype属性も用意しましたのでよかったら見てみてください。タップするとデフォルトで出るキーボードが変わったりします。


それから新しくサポートされたものではRangeがあります。RangeはMobile SafariのデフォルトUIだとボタンの大きさが小さくて正直使いづらいです。
PCだとRangeのバーの部分(ボタンじゃない部分)をクリックすると、その位置までボタンが飛んできてそのままスムーズに入力できるのですが、Mobile Safariの場合だとバーがアクティブの状態になって何も起こりません。
ボタンが小さいので上手く押せず、バーがアクティブになって動かしづらいということがあるので、使うときはスタイルを当ててボタンを大きくしてやるのが良いと思います。


まぁ、Rangeに限らずCheckboxやRadioボタンもデフォルトだとサイズが小さいと思うので、クリック領域を大きくしておくというのは必要なことだと思います。

Input Range Slider

ちなみに、このRangeを使ってiPhoneの待ち受けロックのスライダーを表現している人がいて、おもしろい試みだったので試してみました。
参考:Implementing iPhone's slider unlock with input type="range"

webkit系ブラウザの場合、input要素のスタイルに「-webkit-appearance:none」を与えてやるとブラウザのデフォルトのUI画像を消すことができます(もちろんCheckboxやRadioも)。これでとりあえず消しておいて、後はborder-radiusや-webkit-gradientなどでガシガシそれっぽい画にしていきます。


また、Rangeのボタンは専用のクラス「::-webkit-slider-thumb」でスタイルを当てることができます。これも同じように色々とスタイルを当てていってスライドボタンっぽいUIに近づけていきます。
参考にしたエントリーではボタンに矢印の画像を使っていたのですが、ここは前編でも紹介した「Web Symbols Typeface」を使って画像なしで作りました。
「input[for='range']::-webkit-slider-thumb」に直接contentプロパティを指定できないので、「:before」と「:after」クラスを利用して作っています。


次に、「Slide to unlock」という文字ですが、これはCSS AnimationとMaskをつかってキラっと光る感じのエフェクトをつけています。ここまで画像やJavascriptを使わずに作れるのが面白いですね。
Rangeのサンプルでつくったスライダーは右端までスライドさせるとボタンが左端に戻って、文字が「Unlocked!」に変わりますがそこはさすがにJavascriptを使っています。
shadowなどの透過系の処理をけっこうかけていたりするのであまり滑らかには動かせないのが残念ですが、面白い試みだと思いました。


→ Input Range Slider Demo
HTMLとCSSはこんな感じです。

<div class="slider">
  <input type="range" value="0">
  <p>Slide to unlock</p>
</div>
/* スライダーをのせるベースを描く */
.slider {
  width:286px;
  padding:17px;
  margin-left:0;
  border-top:1px solid #333;
  border-bottom:1px solid #333;
  background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #777), color-stop(0.5, #444), color-stop(0.501, #333), color-stop(1, #000));
  box-shadow:inset 0 1px 0 rgba(255,255,255,0.3);
}
/* スライダーの背景を描く */
.slider input {
  -webkit-appearance:none;
  position:absolute;
  display:block;
  width:280px;
  height:46px;
  padding:3px;
  margin:0;
  border:0;
  border-radius:12px;
  background-image:-webkit-gradient( linear, left top, left bottom, color-stop(0, #000), color-stop(1, #444));
  box-shadow:inset 0 2px 5px #000, 0 1px 1px rgba(255,255,255,0.5);
}
/* スライダーのボタンのベースを描く */
.slider input::-webkit-slider-thumb { 
  -webkit-appearance:none;
  position:relative;
  z-index:100;
  width:68px;
  height:46px;
  border-radius:10px;
  background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #fefefe), color-stop(0.49, #dddddd), color-stop(0.50, #d1d1d1), color-stop(1, #a1a1a1));
  background-repeat:no-repeat;
  background-position:50%;
  box-shadow:inset 0 -1px 1px rgba(255,255,255,0.5), inset 0 1px 0 #fff;
}
/* ボタンのアイコンを描く (@font-faceでWebSymbolsRegularを読み込んでおく) */
.slider input::-webkit-slider-thumb:before,
.slider input::-webkit-slider-thumb:after {
  position:absolute;
  display:block;
  content:'j';
  width:68px;
  padding:9px 0;
  line-height:1;
  font-size:26px;
  font-family:'WebSymbolsRegular';
  color:#848484;
  text-align:center;
}
.slider input::-webkit-slider-thumb:before {
  text-shadow:0 1px 0 rgba(255,255,255,0.9), 0 -1px 0 rgba(0,0,0,0.7);
}
.slider input::-webkit-slider-thumb:after {
  color:#fff;
  -webkit-mask-image:-webkit-linear-gradient(top, rgba(0,0,0,0.3), rgba(0,0,0,0.3) 49%, rgba(0,0,0,0) 50%, rgba(0,0,0,0));
}
/* スライダーに「Slide to unlock」の文字をのせる */
.slider p {
  position:relative;
  width:217px;
  height:46px;
  margin:0;
  padding:3px 1px 3px 65px;
  background:transparent;
  color:#fff;
  font-size: 22px;
  text-align:center;
  line-height:52px;
  vertical-align:middle;
  -webkit-user-select:none;
  -webkit-mask-image:-webkit-gradient(linear, left top, right top, color-stop(0, rgba(0,0,0,0.3)), color-stop(0.4, rgba(0,0,0,0.3)), color-stop(0.49, rgba(0,0,0,1)), color-stop(0.51, rgba(0,0,0,1)), color-stop(0.6, rgba(0,0,0,0.3)), color-stop(1, rgba(0,0,0,0.3)));
  -webkit-mask-size:500px;
  -webkit-mask-repeat:no-repeat;
  -webkit-animation-timing-function:ease-in;
  -webkit-animation:text-spotlight 2.5s infinite;
}
/* アニメーションで文字をキラっとさせる */
@-webkit-keyframes text-spotlight {  
  0% {-webkit-mask-position: -200px;}
  100% {-webkit-mask-position: 70px;}
}
オン・オフを切り替えるToggleボタン

アンロックスライダーの他にもネイティブっぽいUIをいくつか作ってみました。オン・オフを切り替えるToggleボタンや複数の選択肢がある場合に使うRadio Toggleボタン、それからセルの右側にチェックマークがつくセレクトUIです。
まずはオン・オフを切り替えるToggleボタンです。これは非常に簡単です。


checkboxのデフォルトUIをさっきのスライダーと同じように「-webkit-appearance:none」で消して、背景にオンとオフがつながった画像を敷きます。あとは大きさを調整してborder-radiusで角丸にするだけでそれっぽくなります。
オンにしたときつまりcheckedになったときに表示も切り替えたいので擬似クラスを使って背景をずらして完成です。
→ Toggle Button Demo

input[type='checkbox'] {
  -webkit-appearance:none;
  display: block;
  width: 77px;
  height: 27px;
  background: url(toggle.png) no-repeat -51px 0;
  border-radius: 30px;
  -webkit-background-size: 128px 27px;
  -webkit-transition: 0.3s;
}
input[type='checkbox']:checked {
  background-position: 0 0;
}
複数の選択肢がある場合に使うToggle Radioボタン

これはおなじみのchecked擬似クラスと間接セレクタの組み合わせです。ラベル要素にボタンっぽいスタイルを当てて、checked擬似クラスで切り替えます。
Lable要素の横幅はボタンの数によって合わせます。
→ Toggle Radio Buttons Demo

<input type="radio" name="button" id="button1">
<input type="radio" name="button" id="button2">
<input type="radio" name="button" id="button3">
<label for="button1" onclick="">1</label>
<label for="button2" onclick="">2</label>
<label for="button3" onclick="">3</label>
input {
  display:none;
}
label {
  display:inline-block;
  width:33%;
  padding:12px 0 11px;
  border-top:1px solid #aaa;
  border-right:1px solid #b5b6b5;
  border-bottom:1px solid #999;
  text-align:center;
  font-weight:bold;
  font-family:sans-serif;
  color:#7f7f7f;
  background:-webkit-linear-gradient(top, #fcfcfc, #ccc);
  text-shadow:0 1px 0 #fff;
  box-shadow:inset 1px 0 0 #f6f6f6;
  cursor:pointer;
}
label:first-of-type {
  border-left:1px solid #b5b6b5;
  -webkit-border-top-left-radius:7px;
  -webkit-border-bottom-left-radius:7px;
}
label:last-of-type {
  -webkit-border-top-right-radius:7px;
  -webkit-border-bottom-right-radius:7px;
}
#button1:checked ~ label[for='button1'],
#button2:checked ~ label[for='button2'],
#button3:checked ~ label[for='button3'] {
  background:-webkit-linear-gradient(top, #3c77da, #407ee6 49%, #4d89e8 50%, #7aaceb);
  box-shadow:inset 0 7px 8px rgba(0,0,0,0.37);
  color:#fff;
  text-shadow:0 -1px 0 rgba(0,0,0,0.3);
}
セルの右側にチェックマークがつくセレクトUI

これもRadio Toggleボタンと同じようにchecked擬似クラスと間接セレクタの組み合わせです。そのままサンプルだけ書いてもつまらないので、iOS5 WebApp Demoではカラーテーマを選択できるようにしています。
チェックマークはWeb Symbols Typefaceを使って、:after擬似クラスで追加しています。
→ Theme Selector Demo

<input type="radio" name="color" id="red">
<input type="radio" name="color" id="blue">
<input type="radio" name="color" id="yellow">
<div>
  <label for="red" onclick="">Red</label>
  <label for="blue" onclick="">Blue</label>
  <label for="yellow" onclick="">Yellow</label>
</div>
input {
  display:none;
}
label {
  overflow:hidden;
  display:block;
  padding:15px;
  margin:0;
  font-size:130%;
  border-top:1px solid #fff;
  border-bottom:1px solid #ddd;
  background:-webkit-linear-gradient(top, #f9f9f9, #eee);
}
label:first-child {
  -webkit-border-top-left-radius:8px;
  -webkit-border-top-right-radius:8px;
}
label:last-child {
  -webkit-border-bottom-left-radius:8px;
  -webkit-border-bottom-right-radius:8px;
}
div {
  border-radius:7px;
  box-shadow:0 2px 5px rgba(0,0,0,0.4);
}
#red:checked ~ label[for='red']:after,
#blue:checked ~ label[for='blue']:after,
#yellow:checked ~ label[for='yellow']:after {
  float:right;
  padding:0 5px;
  content:'.';
  color:#385487;
  font-family:'WebSymbolsRegular';
}

Inline SVGとSVG icons

iOS5のMobile SafariからはInlineでSVGを描画できるようになりました。SVGをイメージとして読み込んだりすることは今までもできたようですが、InlineなのでHTMLにそのまま埋め込むことが出来るようになりました。
具体的にはこんな感じです。

<html>
<head>
  <title>Inline SVG</title>
<head>
<body>
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="48" height="48">
    <path fill="#000" stroke="none" d="M15.999,22.77l-8.884,6.454l3.396-10.44l-8.882-6.454l10.979,0.002l2.918-8.977l0.476-1.458l3.39,10.433h10.982l-8.886,6.454l3.397,10.443L15.999,22.77L15.999,22.77z" transform="matrix(1.2,0,0,1.2,4,4)"></path>
  </svg>
</body>
</html>

SVGの利点はなんといってもベクターデータなので伸縮してもグラフィックが劣化しない点でしょうか。それからSVGの要素に対して様々なフィルターエフェクトを与えられる点も面白いです。
ですが、Mobile SafariではFilterが上手く動いていないようにも感じました。最近ではIE10でSVG Filter Effectをつかったデモなどがあがっていたりしていますが、今後ますますSVGに対応していってもらえることでデザイナーの表現の幅も広がっていけるように思います。


ちなみに、iOS5 WebApp DemoではいくつかサンプルのSVGアイコン画像を表示していますが、これらはRaphaëlというSVG JavaScript LibraryのサイトFree Iconsからお借りしました。
それからiOS5 WebApp DemoのInline SVGタブですが、インラインSVGを並べすぎて切り替えの描画にものすごく時間がかかってしまいます。すいません。


表示されたアイコンの色を動的に変えたり、グラデーションをかけたり簡単にできるので便利です。アイコンをタップするとパスデータを見ることができるようにしました。
本当はフィルターをバシバシ切り替えていくというデモを用意したかったのですが、、、対応が待ち遠しいです。

縦書きの読みもの表現

最後に、iOS5 WebApp Demoで新たに紹介した「縦書きの読みもの表現」について紹介しようと思います。
iOS5 Mobile Safariでは「writing-modeプロパティ」に対応しました。writing-modeには「horizontal-tb」「vertical-rl」「vertical-lr」という値を指定することができます。
horizontal-tbはつまり、horizontal -> 横書きで tb -> top bottomということですね。同じようにvertical-rlは縦書きで右から左に流れる、vertical-lrは縦書きで左から右に流れるということになります。


縦書きにしたときの数字やローマ字の処理はさまざまあると思いますが、今回はtext-orientationプロパティに「upright」を指定して縦に並ぶようにしました。


日本語で縦書きといえばやっぱり明朝体のほうが自然だと思います。iOS5からはフォントに「ヒラギノ明朝 ProN」がサポートされました。
これらを用いてiOS5 WebApp Demoでは縦書きのブックリーダー風なUIを作ってみました。


ここで一つ問題がありまして、縦書きで長い文章を表示するときに横にスクロールするようにするとデフォルトで右側にスクロールがある状態になります。しかし、通常縦書きの読み物は右から左にという読む移動をします。
これをCSSで解決するのはなかなか難しいです。なのでデモではJavascriptでスクロールを強制的に左側に移動させる処理を加えています。
(でもよく考えたらスクロールじゃなくて、お得意のInput要素を使ったUIでページング処理すれば問題ないように思ったので、また今度試してみようと思います)


それから、デモにはフルスクリーンビューに切り替えるボタンも用意してみました。
ここまで来るとHTMLをローカルキャッシュさせて、さらにローカルのデータベースにしおりやブックマークを保存する機能なんかも付けて、オフライン・ブックリーダー・アプリまでできそうだなぁと思いました。
暇な方はつくってみて欲しいところです。つくってみた方はお知らせください!


シンプルなデモも用意しました。

→ Book Reader UI Demo


まとめ

前編と後編に分けてiOS5 Mobile SafariがサポートしたHTML・CSSとそれらを使ったテクニックをたくさん紹介しましたが、書いているうちにアレコレ詰め込みたくなってしまいました。
ちょっと散漫な感じになってしまってすいません。他にも使われているちょっとしたテクニックなどを別の機会に紹介しようと思います。


今回はあえてネイティブアプリのような振る舞いをするUIを再現することに執着しているように感じるかもしれませんが、個人的にはWebAppでネイティブアプリと同じようなものを作ってもしょうがないと思っています。
WebAppにはWebAppに最適なUIを作る必要があると思うからです(それはもちろんどんなアプリであっても同じだと思いますが)。
今回ネイティブアプリのようなUIをデモなどでつくった理由としては、紹介したようなテクニックがどういったことが実現可能かという基準ラインのようなものを示すのに調度良いと考えたからです。
UIパターンというのははあくまで手段であってそれが必ずしもゴールになると考えて設計するのは、やはり間違いでしょう。
難しいこといいましたが、「えっ、こんな表現もできるの!?」と思えるような、使っていて楽しくなるUIというのを考えていきたいです。


それから、今回はCSSを使ったテクニックを中心に紹介しましたが、iOS5ではJavascriptでもできることの幅がものすごく広がっています。もし、時間があればそちらの方もいろいろ試したいと思います。