Google モバイルサイトや Disney.com のオフキャンバスっぽいメニュー
Google のスマートフォンサイトがリニューアルされたというので見てみたら、メインメニューの表示方法が面白い感じになっていたので自分でも作ってみました。
ちなみに、先日レスポンシブウェブデザインに変更した Disney.com も、表示幅が 1024px 以下だと似たようなメニューの表示方法になります。
作ったものは以下。
サンプルなので HTML は適当に。
実際にはもっと複雑になるでしょうが、動きを試すためのものなのでこんな感じで。
<div id="nav" class="globalnav">
<a href="#">Navigation</a>
</div>
<div id="main" class="content">
<div class="switcher">
<button id="toggleMenu">☰</button>
</div>
Main Content
</div>
button#toggleMenu
をクリック(タップ)したらメニューの開閉を行います。
jQuery(function ($) {
$('#toggleMenu').on('click', function (e) {
e.preventDefault();
$('body').toggleClass('showMenu');
});
});
遷移アニメーションなどは CSS 側でやるので、JavaScript 側ではメニューが開いているかどうかという状況を判別するクラス名を付け外しするだけにします。
(サンプルでは使ってますが、特に jQuery 使う必要はないです)
ではこの動きの肝である CSS を。
.globalnav {
position: fixed;
top: 0;
left: 0;
z-index: -1;
width: 160px;
height: 100%;
background: #fcc;
visibility: hidden;
transition: visibility 0s linear 0.2s;
}
.showMenu .globalnav {
z-index: 1;
visibility: visible;
transition: z-index 0s linear 0.2s;
}
.content {
height: 900px;
background: #ccf;
transform: translateX(0px);
transition: transform 0.2s linear;
}
.showMenu .content {
transform: translateX(160px);
}
通常の状態(body
に特にクラス名を付与していない状態)では、div.globalnav
は visibility: hidden;
の指定により非表示となっており、position: fixed; z-index: -1;
の指定で div.content
の下(レイヤー的な意味)にあって隠されています。
逆に言うと div.content
を被せることによって見えなくしているわけです。
メニューを表示している状態(body
に showMenu
というクラス名が付いている状態)では、div.content
は transform: translateX(160px);
によって、あらかじめ指定しておいたメニューの幅の分、右に移動します。
そしてメニューは visibility: visible; z-index: 1;
によって div.content
より上のレイヤーになって表示されます。
div.content
は普通に transition: transform;
しているわけですが、ここでは transition-duration
に 0.2s
を指定しています。
この時間分、div.globalnav
のトランジションにディレイをかけます。
そうしないと body
にクラス名 showMenu
が付いた瞬間に一番上のレイヤーになってしまって見た目が悪いです。
メニュー部分の transition-duration
が 0s
なのは、これらは状態変化にディレイをかけるためで、遷移アニメーションさせるためのものではないからだと思われます。
メニュー部分は状態によって違うトランジションの指定を行います。
body
に showMenu
というクラス名が付いていないとき、つまり、閉じる動作のときには visibility
を対象とします。
これがないと閉じようとした瞬間にメニュー部分が見えなくなって見栄えが悪いです。
そもそもなぜここに visibility
が指定されているのかということですが(なくても期待通りに動くのに)、おそらく Android の z-index
バグを回避するためだと思われます。重なった状態の下のレイヤー部分が反応してしますあれです。推測ですけど。
で、body
に showMenu
というクラス名が付いているとき、開く動作の時には z-index
をトランジションの対象にします。
こうすることによって visibility: visible;
は即座に反映されて、開いている途中でもメニュー部分が見えるようになります。そして開ききったら transition-delay: 0.2s;
によって z-index: 1;
になって、メニューを一番上のレイヤーに配置します。
以上が Google のスマートフォンサイトの開閉メニューの仕組みです。たぶん。
ざっと見て作ったので実際のものとは結構違いがありますし、間違って解釈している部分があるかもしれません。
ちゃんと知りたい方は自分で確認してください。