LoginSignup
2
5

More than 5 years have passed since last update.

モバイルブラウザでメニュー表示時にメニューをスムーズにスクロールさせ、コンテンツは位置固定で留める

Posted at

iPhone Safari などのモバイルブラウザで、位置固定されたヘッダの中にあるハンバーガーメニュー(これの良し悪しは置いといて)などにより、メニューがシュッて出てくるウェブページはこのご時世よく見かけますが、以下のことで不満があったりします。

  • メニュー内のスクロールがカクカクする
  • スクロールしたらメニューが途中で途切れる
  • スクロールしたらコンテンツまで一緒にスクロールされてしまう
  • メニューを開いたらコンテンツが一番上まで戻ってしまう
  • 進んだ先のページを元に戻ってメニュー内の別の項目へ行きたいのに再度メニューを開かないといけない

この不満を解消すべくの方法です。あくまでもこの不満は個人的なものなので、みなさんの欲求には当てはまらないかもしれません。

HTML

ヘッダとメニュー以外を #field でくくります。

index.html
<input id="chk_nav" type="checkbox" />
<header>
    <h1>ヘッダ</h1>
    <label for="chk_nav">MENU</label>
</header>
<nav id="nav_global">
    <ul>
        <li>
            <a href="?test=00">メニュー項目00</a>
        </li>
        <li>
            <a href="?test=01">メニュー項目01</a>
        </li>
        <li>
            <a href="?test=02">メニュー項目02</a>
        </li>
    </ul>
</nav>
<div id="field">
    <section>#field の中の内容01</section>
    <section>#field の中の内容02</section>
    <section>#field の中の内容03</section>
</div>

Sass

メニューの開閉は input#chk_nav で管理するので、:checked を使ってシュッと出します。
メニューの背景色はメニュー本体である #nav_global に付けるとメニュー内容が少ない場合にブサイクなので、#field:after で色を付け、一緒にシュッと出します。
開いた際に #field は .nav_open が付いて 100% * 100% の固定となりスクロール不可になり、#nav_open も .nav_open が付いて position:relative となってスクロールがスムーズにできるようになります。

spmenu.sass
#nav_global, #field:after
    +transition-property(transform)
    +transition-duration(.3s)
    +transition-delay(0s)
    +transition-timing-function(ease)
#nav_global
    width: 100%
    position: fixed
    top: 50px
    left: 0
    z-index: 99
    +transform(translateX(100%))

    ul
        margin: 0
        padding: 0

        li
            display: block
            border-bottom: 1px solid #fff

            a
                padding-left: 10px
                display: block
                line-height: 50px
                color: #fff
                text-decoration: none
    &.nav_open
        position: relative
#field
    &:after
        content: ''
        width: 100%
        height: 100%
        display: block
        position: fixed
        top: 0
        left: 0
        z-index: 98
        background-color: rgba(#000, .7)
        +transform(translateX(100%))
    &.nav_open
        width: 100%
        height: 100%
        position: fixed
        top: 0
        left: 0
        z-index: 0
        overflow: hidden
#chk_nav
    display: none

    &:checked+header
        &+#nav_global, &+#nav_global+#field:after
            +transform(translateX(0))

CoffeeScript

Sass で書いた通り、メニューの管理は #chk_nav でするので、.prop('checked') で判断します。
開いた際は、現在のスクロール位置を取得し、#field へ .nav_open を付けて固定化した上でこれをスクロールし、そのままの位置であるかのように見せます。
シュッと出た後を見計らって(Sass で .3s としているので、350ms としてます) #global_nav へ .nav_open を付けてスクロールできるようにします。
閉じた際は、これらの class を解き放ち、開いた際に取得したスクロール位置に戻してやります。

spmenu.coffee
spmenu =
    positions: 0
    fire: ($this) ->
        if $this.prop('checked')
            @positions = $(document).scrollTop()
            $('#field').addClass('nav_open').scrollTop(@positions)
            $('#nav_global')
                .delay(350).queue ->
                    $(this).addClass('nav_open').dequeue()
                    $('html, body').scrollTop(0)
                    return
        else
            $('#nav_global').removeClass('nav_open')
            $('#field').removeClass('nav_open')
            $('html, body').scrollTop(spmenu.positions)
        return
$ ->
    $('#chk_nav').on 'change', ->
        spmenu.fire($(this))
        return
    return

生成された JavaScript も置いておきます。

spmenu.js
(function() {
  var spmenu;

  spmenu = {
    positions: 0,
    fire: function($this) {
      if ($this.prop('checked')) {
        this.positions = $(document).scrollTop();
        $('#field').addClass('nav_open').scrollTop(this.positions);
        $('#nav_global').delay(350).queue(function() {
          $(this).addClass('nav_open').dequeue();
          $('html, body').scrollTop(0);
        });
      } else {
        $('#nav_global').removeClass('nav_open');
        $('#field').removeClass('nav_open');
        $('html, body').scrollTop(spmenu.positions);
      }
    }
  };

  $(function() {
    $('#chk_nav').on('change', function() {
      spmenu.fire($(this));
    });
  });

}).call(this);

サンプルを置いておきます

2
5
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5