久々にこの手のネタ書いた気がしますけども… ちょっとしたお遊びなんですが、普段は画面の下の隅に隠れてて、クリック (タップ) で展開、いくつかのショートカットメニューが表示される、しかもスマートフォンだと片手だけで操作しやすいみたいな UI を CSS と超簡単な JavaScript (jQuery 使用) で作ってみたので紹介。多分言葉で言っても伝わりにくいと思いますので実際のサンプルをまずは見てみてください。
現在最新版の Firefox、Safari、Chrome では動くと思います。あと手持ちの iOS 5 (iPhone 4S) Safari では動作確認しました。他のスマートフォンとか知らない (CSS の position : fixed に対応してないヤツだと動かない)。IE?何それ美味しいの?
実は友人が ドコモのスマートフォン 「P-07C」 で 「タッチスピードセレクター」 を使ってるのを見て、似たようなの (見た目だけね) を HTML / CSS で作ってみたらどんな感じだろって思ったのがきっかけなんですが、CSS で見た目と動きを作って、JavaScript でメニュー開閉のトリガーだけ操作するって感じで結構、楽に作れました。特に CSS3 のおかげで古いブラウザを考えなければこういうのは楽な時代になりましたね。
では早速、順を追って説明してみたいと思います。
1. メニュー部分の HTML
まずはメニュー部分の HTML を。ソース自体は簡単です。
<div id="menu"> <ul> <li><a href="./"><img src="img/home.png" alt="ホーム" /></a></li> <li><a href="./"><img src="img/search.png" alt="検索" /></a></li> <li><a href="./"><img src="img/tweet.png" alt="ツイート" /></a></li> <li id="openMenu"><img src="img/menu.png" alt="メニューを開く" /></li> <li id="closeMenu">メニューを閉じる</li> </ul> </div>
今回は 3つのメニューに加え、メニュー自体を開く / 閉じるための要素を単純にリストとしてマークアップしました。
2. CSS でメニュー部分の見た目を作る
次に基本的な見た目を作っていきます。メニューのオレンジのボーダーは ul 要素に。そして丸める。各 li 要素も丸い形のボタンっぽくなるようにします。
#menu ul { margin: 0; padding: 0; list-style: none; width: 240px; height: 240px; border-radius: 126px; border: 6px solid #f6a35b; background: #252925; } #menu ul li { width: 40px; height: 40px; border-radius: 22px; border: 2px solid #fff; background: #252925; overflow: hidden; }
ここまでやると、下記のような見た目になるはず。(丸くするなら border-radius : 50% でいいんですが、そうしていないのは iOS Safari で % の値が使えないからです。使えるようになりました)
ちょっとした装飾
CSS3 のプロパティを使ってちょっとだけ見た目をいじってみます。何をするかというと、「ドロップシャドウをつける」。ということで ul、li 各要素に下記のようなスタイルを追加で指定。
#menu ul { margin: 0; padding: 0; list-style: none; width: 240px; height: 240px; border-radius: 126px; border: 6px solid #f6a35b; background: #252925; box-shadow: 0 0 10px rgba(0,0,0,0.4); } #menu ul li { width: 40px; height: 40px; border-radius: 22px; border: 2px solid #fff; background: #252925; overflow: hidden; box-shadow: 0 0 10px rgba(0,0,0,0.4); }
これで影がつきました。
各ボタンの位置を調整
次に、各ボタン (li 要素) を所定の位置に配置します。まずはメインのボタン 3つと、メニューを開くボタンを移動します。先ほどの li に対するスタイルに、「position : relative」 を追加し、さらにそれぞれの li 要素の場所を指定していきます。今回は :nth-child 疑似クラスを使って簡単に。
「li#openMenu」 に指定している 「cursor: pointer」 はメニューを開くボタンはリンクじゃないので、一応マウスカーソルが乗ったときにわかりやすいように。
#menu ul li { width: 40px; height: 40px; border-radius: 22px; border: 2px solid #fff; background: #252925; overflow: hidden; box-shadow: 0 0 10px rgba(0,0,0,0.4); position: relative; } #menu ul li:nth-child(1) { top: -25px; left: 110px; } #menu ul li:nth-child(2) { top: -30px; left: 185px; } #menu ul li:nth-child(3) { top: 0; left: 220px; } #menu ul li#openMenu { top: 50px; left: 10px; cursor: pointer; }
ここまでで下記のように。閉じるボタンが開くボタンと重なっていますが気にしない。
閉じるボタンの調整
閉じるボタンはメニューが展開されている状態の時、オレンジ枠内をクリックしたら動作させたいので、他とはちょっと違う配置のしかたをします。ということでまずは下記のようなスタイルを指定します。
#menu ul li#closeMenu { width: 200px; height: 200px; border-radius: 100px; top: -140px; left: 0px; }
これで下記のようになりますね。
この丸の中が閉じるボタンのクリック領域になります。あまりメニューのボタンと近づけてしまうと、メニューを操作しようとしたら閉じちゃうってことになるので、少しスペースをあけるのがポイントです。
で、このままだと閉じる領域が目立ちすぎるので下記のようにスタイルを追加して溶け込ませます。
#menu ul li#closeMenu { width: 200px; height: 200px; border-radius: 100px; top: -140px; left: 0px; border: none; background-color: transparent; box-shadow: none; text-align: center; color: #252925; }
ここまででこんな感じ。
ただ、このままだと実は見えていないだけで開くボタンの上に閉じるボタンが重なってしまっているので注意。後のステップでそれを解消しますが、今はこれで置いときます。
3. メニューの動きを作っていく
次に動きをつけていきますよ。
前のステップで、3つのボタンと開くボタンを対面位置に配置したのは意味があって、メニューが閉じてるときはこの円形メニュー自体が 180度回転していて、開くボタンが右上にある状態に。で、開くボタンを押すと、回転が元に戻って 3つのメニューが右上になると。その状態で円形メニューの、時計で言うところの 「3時 ~ 12時」 部分を画面外に出して隠してやれば、今回のようなメニューが回転して出てくるっていう UI にできるわけ。
ということで、まずは 180度回転させてみます。上で出てきた ul 要素に対するスタイルに、下記のように追加します。
#menu ul { margin: 0; padding: 0; list-style: none; width: 240px; height: 240px; border-radius: 126px; border: 6px solid #f6a35b; background: #252925; box-shadow: 0 0 10px rgba(0,0,0,0.4); -moz-transform: rotate(180deg); -webkit-transform: rotate(180deg); transform: rotate(180deg); }
transform プロパティを使用しますが、ベンダープレフィックスがないとまだ動かないのであわせて記述。これで下記のように回転しますね。
開閉の切り替えのトリガーを jQuery で
この状態から、開くボタンをクリックしたときに元の状態に戻さないといけません。何をトリガーにするかですが、すぐに思いつく方法として、開くボタンクリック時に ul 要素に class をつけて、それに対して回転を元に戻すスタイルを指定してあげれば簡単です。class つけるとかは jQuery を使っておけば超簡単。
まずは開くボタンクリック時に class をつけるように下記のように head 要素内に記述。
<!-- ↓jQueryの読み込み↓ --> <script src="http://www.google.com/jsapi"></script> <script>google.load("jquery", "1.7");</script> <!-- ↓class を付けたり消したり↓ --> <script> $("#openMenu").click(function () { $("#menu, #menu ul").addClass("active"); }); </script>
これで、開くボタンをクリックすると、「active」 という class が div#menu と ul につきます。なんで div#menu にも?っていうのは後でわかります。
当然、今度は閉じるボタンをクリックした際に今度はこの class を消さないといけないので、下記のように追加。
<script> $("#openMenu").click(function () { $("#menu, #menu ul").addClass("active"); }); $("#closeMenu").click(function () { $("#menu, #menu ul").removeClass("active"); }); </script>
ついでに、先に 「今のままだと開くボタンの上に見えない閉じるボタンが重なっちゃってるよ」 と書きましたが、これを解消するため、メニューが閉じている状態では必要ない閉じるボタンを消しちゃいます。初期状態で li#closeMenu を非表示になるように下記のように追加。同時に開閉の切り替えに応じて表示非表示を切り替える記述も加えます。
<script> $(function(){ $("#closeMenu").hide(); $("#openMenu").click(function () { $("#menu, #menu ul").addClass("active"); $("#closeMenu").show(); }); $("#closeMenu").click(function () { $("#menu, #menu ul").removeClass("active"); $("#closeMenu").hide(); }); }); </script>
ということで、JavaScript 部分の完成版は下記の通り。
<script src="http://www.google.com/jsapi"></script> <script>google.load("jquery", "1.7");</script> <script> $(function(){ $("#closeMenu").hide(); $("#openMenu").click(function () { $("#menu, #menu ul").addClass("active"); $("#closeMenu").show(); }); $("#closeMenu").click(function () { $("#menu, #menu ul").removeClass("active"); $("#closeMenu").hide(); }); }); </script>
class がついているときのスタイルを指定
jQuery でここまでやったら、それぞれの class がついているときのスタイルを指定します。まずは ul の回転を元に戻す指定から。
#menu ul.active { -moz-transform: rotate(0deg); -webkit-transform: rotate(0deg); transform: rotate(0deg); }
これで開くボタン、閉じるボタンそれぞれをクリックするごとにメニューがクルクル回転すると思いますが、パッと切り替わってしまうだけでメニューが回転しているのがわからないと思いますので、そこの動きを調整します。使うのは transition プロパティ。こいつもベンダープレフィックスがないとまだ動きませんので併記します。
細かい解説は置いといて、ul に対して下記のようにスタイル指定します。active 時も同様。
#menu ul { margin: 0; padding: 0; list-style: none; width: 240px; height: 240px; border-radius: 126px; border: 6px solid #f6a35b; background: #252925; box-shadow: 0 0 10px rgba(0,0,0,0.4); -moz-transform: rotate(180deg); -webkit-transform: rotate(180deg); transform: rotate(180deg); -moz-transition: -moz-transform 0.5s ease-out; -webkit-transition: -webkit-transform 0.5s ease-out; transition: transform 0.5s ease-out; } #menu ul.active { -moz-transform: rotate(0deg); -webkit-transform: rotate(0deg); transform: rotate(0deg); -moz-transition: -moz-transform 0.5s ease-out; -webkit-transition: -webkit-transform 0.5s ease-out; transition: transform 0.5s ease-out; }
はい、これでヌルヌル回転するようになりましたね。完成は近いですよ。
4. 仕上げ : メニューを左下に配置する
最後にメニューを画面左下に固定し、動きにもう一工夫加えます。左下に固定するのは簡単。position プロパティを使います。この場所指定は ul を内包する div に対して行ってみます。
#menu { position: fixed; margin: 0; padding: 0; left: -180px; bottom: -180px; }
はい、左下にめり込みましたね。
で、単純に常に円の右上 4分の1 (時計でいう 12時 ~ 3時部分) 程度を表示させるなら、left、bottom の値は本来、-120px (ul の縦横サイズの半分) くらいになると思いますが、それだとメニューが閉じた状態で表示されている部分が多すぎて邪魔なので、閉じているときはもっとめり込ませてしまいます。なので -180px 指定しています。
ただ、このままの位置で回転させると、当然メニューが切れてしまいますので、開いているときはこのめり込み具合を調整します。そのために下記の記述を加えます。先ほど、開閉切替時に div#menu にも active をつけていた理由はこのためです。出てくる動きもスムーズにするため、transition プロパティを使います。
div.active { left: -100px !important; bottom: -100px !important; -moz-transition: left 0.5s ease-out, bottom 0.5s ease-out; -webkit-transition: left 0.5s ease-out, bottom 0.5s ease-out; transition: left 0.5s ease-out, bottom 0.5s ease-out; }
あわせて、閉じるときにも開くとき同様、動きをスムーズにしたいので、#menu にも transition プロパティを足しておきます。
#menu { position: fixed; margin: 0; padding: 0; left: -180px; bottom: -180px; -moz-transition: left 0.5s ease-out, bottom 0.5s ease-out; -webkit-transition: left 0.5s ease-out, bottom 0.5s ease-out; transition: left 0.5s ease-out, bottom 0.5s ease-out; }
これで、開くボタンを押すと、回転しながらメニューがせり出してくるはず。閉じるとその逆に動きます。
ということで、CSS の完成版は下記の通り。
#menu { position: fixed; margin: 0; padding: 0; left: -180px; bottom: -180px; -moz-transition: left 0.5s ease-out, bottom 0.5s ease-out; -webkit-transition: left 0.5s ease-out, bottom 0.5s ease-out; transition: left 0.5s ease-out, bottom 0.5s ease-out; } #menu ul { margin: 0; padding: 0; list-style: none; width: 240px; height: 240px; border-radius: 126px; border: 6px solid #f6a35b; background: #252925; box-shadow: 0 0 10px rgba(0,0,0,0.4); -moz-transform: rotate(180deg); -moz-transition: -moz-transform 0.5s ease-out; -webkit-transform: rotate(180deg); -webkit-transition: -webkit-transform 0.5s ease-out; transform: rotate(180deg); transition: transform 0.5s ease-out; } #menu ul li { position: relative; width: 40px; height: 40px; border-radius: 22px; border: 2px solid #fff; background: #252925; overflow: hidden; box-shadow: 0 0 5px rgba(0,0,0,0.4); } #menu ul li:nth-child(1) { top: -25px; left: 110px; } #menu ul li:nth-child(2) { top: -30px; left: 185px; } #menu ul li:nth-child(3) { top: 0; left: 220px; } #menu ul li#openMenu { top: 50px; left: 10px; cursor: pointer; } #menu ul li#closeMenu { width: 200px; height: 200px; border-radius: 100px; border: none; background-color: transparent; box-shadow: none; top: -140px; left: 0px; text-align: center; color: #252925; } #menu ul.active { -moz-transform: rotate(0deg); -moz-transition: -moz-transform 0.5s ease-out; -webkit-transform: rotate(0deg); -webkit-transition: -webkit-transform 0.5s ease-out; transform: rotate(0deg); transition: transform 0.5s ease-out; } div.active { left: -100px !important; bottom: -100px !important; -moz-transition: left 0.5s ease-out, bottom 0.5s ease-out; -webkit-transition: left 0.5s ease-out, bottom 0.5s ease-out; transition: left 0.5s ease-out, bottom 0.5s ease-out; }
実際に動作するサンプルは下記で確認できます。
上記サンプルのファイル一式は下記から落とせますので適当にいじってみてください。
ちなみに今回のやつ、デザインは Dribbble に投稿された下記がイケてたのでインスパイアされてみた。
なお、サンプルは CSS を書きながらボタンの配置とかの見た目を目分量で作っていっていますので多分、微妙に並びがずれていたりするかもしれませんがその辺はご愛敬。あと、自分が左利きだからか左下に配置したけど、もしかしたら片手操作の時使う手が逆の人が大半なのでは…と作り終わってから気がつきましたが、その辺は気にしない。
ということで何かの参考にでもなれば。