メニューを閉じたときに元いた位置から閲覧できるようにするJavascript

by Wataru Adachi

HTML

<div id="wrapper">
  <header>
    <button type="button" id="openMenu">
      <span></span>
      <span></span>
      <span></span>
    </button>
    <h1>ハンバーガーボタン</h1>
    <nav>
      <ul>
        <li><a href="#">リスト01</a></li>
        <li><a href="#">リスト02</a></li>
        <li><a href="#">リスト03</a></li>
        <li><a href="#">リスト04</a></li>
        <li><a href="#">リスト05</a></li>
        <li><a href="#">リスト06</a></li>
        <li><a href="#">リスト07</a></li>
        <li><a href="#">リスト08</a></li>
        <li><a href="#">リスト09</a></li>
        <li><a href="#">リスト10</a></li>
        <li><a href="#">リスト11</a></li>
        <li><a href="#">リスト12</a></li>
        <li><a href="#">リスト13</a></li>
        <li><a href="#">リスト14</a></li>
        <li><a href="#">リスト15</a></li>
        <li><a href="#">リスト16</a></li>
        <li><a href="#">リスト17</a></li>
        <li><a href="#">リスト18</a></li>
        <li><a href="#">リスト19</a></li>
        <li><a href="#">リスト20</a></li>
      </ul>
    </nav>

    <div id="layer"></div><!-- #layer -->

  </header>

  <main>
    <div class="inner">
      <p>この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        <h2>見出しh2</h2>
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
        <h3>見出しh3</h3>
        この文章はダミーテキストです。文字サイズや行間などを確認するために入れています。これで50文字です。
       ...

CSS

/* bodyの固定用 */
html.fixed,
body.fixed { /* ドロワーが開いた状態 */
  position: fixed;
  width: 100%;
  height: 100%;
}

header {
  width: 100%;
  height: 60px;
  background-color: #666;
  color: #fff;
  position: fixed;
  top: 0;
  z-index: 3;
}

header #openMenu {
  width: 35px;
  height: 40px;
  background-color: #666;
  position: absolute;
  top: 10px;
  left: 10px;
  cursor: pointer;
  outline: none;
  padding: 0;
  border: 0;
  appearance: none;
  z-index: 4;
}

header #openMenu span {
  display: block;
  width: 100%;
  height: 5px;
  background-color: #fff;
  -moz-border-radius: 3px;
  -webkit-border-radius: 3px;
  border-radius: 3px;
}

header #openMenu span:nth-child(1) {
  margin-top: 0;
}

header #openMenu span:nth-child(2) {
  margin-top: 5px;
}

header #openMenu span:nth-child(3) {
  margin-top: 5px;
}

header h1 {
  font-size: 1em;
  text-align: center;
  line-height: 60px;
	margin: 0;
}

header nav {
  position: fixed;
  /* ここは必ずfixed */
  top: 60px;
  /* top,left,right,bottomを全て0で指定 */
  left: -80%;
  right: 0;
  bottom: 0;
  overflow-y: scroll;
  /* fixed内が溢れたときにスクロール */
  -webkit-overflow-scrolling: touch;
  /* iphone慣性スクロール用 */
  width: 60%;
  background-color: rgba(0, 0, 0, 0.8);
  z-index: 2;
  -moz-transition: all 0.2s linear;
  -o-transition: all 0.2s linear;
  -webkit-transition: all 0.2s linear;
  transition: all 0.2s linear;
}

header nav.open { /* ドロワーが開いた状態 */
  left: 0;
}

header nav ul {
  margin: 0;
  padding: 0;
  list-style-type: none;
}

header nav ul li {
  width: 100%;
  height: 45px;
  line-height: 45px;
  padding-left: 1em;
  border-bottom: 1px solid #666;
}

header nav ul li a {
  display: block;
  width: 100%;
  height: 100%;
  color: #fff;
}

header nav ul li a:hover {
  color: #fff;
  text-decoration: underline;
}

header nav ul li+li {
  border-top: 1px solid #999;
}

header #layer {
  position: fixed;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.4);
  z-index: 1;
  display: none;
}

header...

TypeScript

document.addEventListener('DOMContentLoaded', (): void => {

  const body: HTMLElement | null = document.querySelector('html') || document.querySelector('body');
  const menuBtn: HTMLElement | null = document.getElementById('openMenu');
  const nav: HTMLElement | null = document.querySelector('nav');
  const layer: HTMLElement | null = document.getElementById('layer');
  let scrollPos: number = 0;

  function getScroll() {
    return Math.max(document.documentElement.scrollTop, document.body.scrollTop, window.scrollY);
  }

  menuBtn?.addEventListener('click', (): void => {

    if (body?.classList.contains('fixed') || nav?.classList.contains('open') || layer?.classList.contains('open')) {
      body.classList.remove('fixed');
      nav.classList.remove('open');
      layer.classList.remove('open');
    } else {
      scrollPos = getScroll();
      body?.classList.add('fixed');
      nav?.classList.add('open');
      layer?.classList.add('open');
    }

    if (scrollPos !== 0) {
      body?.style.top = `-${String(scrollPos)}px`;
    }

  });

  layer?.addEventListener('click', (): void => {

    body?.classList.remove('fixed');
    nav?.classList.remove('open');
    layer?.classList.remove('open');


    if (scrollPos !== 0) {
			body?.style.top = '';
      window.scrollTo(0, scrollPos);
    }
  });

});