2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?