Unformed Building

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">&#9776;</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.globalnavvisibility: hiddenの指定により非表示となっており、position: fixed; z-index: -1の指定でdiv.contentの下(レイヤー的な意味)にあって隠されています。
逆に言うとdiv.contentを被せることによって見えなくしているわけです。

メニューを表示している状態(bodyshowMenuというクラス名が付いている状態)では、div.contenttransform: translateX(160px)によって、あらかじめ指定しておいたメニューの幅の分、右に移動します。
そしてメニューはvisibility: visible; z-index: 1によってdiv.contentより上のレイヤーになって表示されます。

div.contentは普通にtransition: transformしているわけですが、ここではtransition-duration0.2sを指定しています。
この時間分、div.globalnavのトランジションにディレイをかけます。
そうしないとbodyにクラス名showMenuが付いた瞬間に一番上のレイヤーになってしまって見た目が悪いです。

メニュー部分のtransition-duration0sなのは、これらは状態変化にディレイをかけるためで、遷移アニメーションさせるためのものではないからだと思われます。

メニュー部分は状態によって違うトランジションの指定を行います。
bodyshowMenuというクラス名が付いていないとき、つまり、閉じる動作のときにはvisibilityを対象とします。
これがないと閉じようとした瞬間にメニュー部分が見えなくなって見栄えが悪いです。
そもそもなぜここにvisibilityが指定されているのかということですが(なくても期待通りに動くのに)、おそらくAndroidのz-indexバグを回避するためだと思われます。重なった状態の下のレイヤー部分が反応してしますあれです。推測ですけど。

で、bodyshowMenuというクラス名が付いているとき、開く動作の時にはz-indexをトランジションの対象にします。
こうすることによってvisibility: visibleは即座に反映されて、開いている途中でもメニュー部分が見えるようになります。そして開ききったらtransition-delay: 0.2sによってz-index: 1になって、メニューを一番上のレイヤーに配置します。


以上がGoogleのスマートフォンサイトの開閉メニューの仕組みです。たぶん。
ざっと見て作ったので実際のものとは結構違いがありますし、間違って解釈している部分があるかもしれません。
ちゃんと知りたい方は自分で確認してください。