JSFiddle - React, Tailwind, and code Playground

by junhui

HTML

<div class="absolute-layer wrapper">
    <div class="absolute-layer sub-wrapper">
        <nav>
            <div class="absolute-layer scrollable-y">
                Navigation
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
                <p>Lorem, ipsum dolor.</p>
            </div>
        </nav>
        <header>
            <button id="menuButton">
                Toggle Menu
            </button>
            Header
        </header>
        <div class="main-content-area absolute-layer scrollable-y">
            <main>
                start
                <br />
                <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus consequuntur aliquid amet. Neque modi
                    voluptate sapiente numquam laborum aut, officiis dignissimos voluptatem maiores eos deleniti! Fuga
                    minus quo aspernatur nulla eligendi eaque voluptate explicabo dolor, vero temporibus similique nam
                    saepe eos doloremque quis voluptates
                    <input type="text" /> officia vel. Nulla mollitia ab, laudantium repudiandae corporis ad corrupti ullam aspernatur atque?
                    Ea, deserunt et! Aliquam doloremque doloribus, placeat qui sequi magnam, fugiat sit at consequuntur
                    porro repellendus quia voluptates molestiae labore est nobis dignissimos, possimus tenetur mollitia
                   ...

CSS

/* Utilites */

/* 
The absolute-layer is useful to create an inner scrollable layer, I
learned from:
https://medium.com/@im_rahul/safari-and-position-fixed-978122be5f29 
*/

.absolute-layer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.scrollable-y {
  -webkit-overflow-scrolling: touch;
  overflow-y: auto;
}

/* Toggle Menu */

/* Both .wrapper and .sub-wrapper is an absolute layer */

.wrapper.menuIsOpen {
  overflow: hidden;
}

.sub-wrapper {
  transition: transform 0.3s ease-out;
}

.wrapper.menuIsOpen > .sub-wrapper {
  transform: translateX(240px);
}

/* Left sidebar - Navigation */

/* 
Notes:
1. Left sidebar sits in the left side of the Main content area,
it's invisible by default. When the menu is open, push the
sub-wrapper right to let the Nav visible in the viewpoint.
2. Nav's inner wrapper should be an abosolute layer and scrollable.
*/

nav {
  width: 240px; /* Fixed width */

  position: absolute;
  top: 0;
  bottom: 0;
  left: -240px; /* Left matches the fixed width */
}

/* Main content area - Header, Main and Footer */

/* 
Notes: 
1. Header sticks in the top of the Main content area.
2. Footer sits inside the .main-content-area so that it's in the end of the content flow.
3. Main content area is an scrollable absolute layer.
*/

header {
  /* Makes sure the header is always in the front of the main content */
  position: relative;
  z-index: 1;

  height: 50px; /* Fixed height */
}

.main-content-area {
  /* PaddingTop matches the height of header */
  padding-top: 50px;
}

/* Presentation Setup */

* {
  box-sizing: border-box;
}

body {
  margin: 0;
}

p {
  font-size: 2em;
  line-height: 1.5;
}

nav {
  background: gold;
}

header {
  background: green;
}

footer {
  background: orchid;

  /* Arbitrary height for presentation */
  height: 100px;
}

JavaScript

const menuButton = document.querySelector("#menuButton");
const wrapper = document.querySelector(".wrapper");
const mainContentArea = document.querySelector(".main-content-area");

/* Toggle Menu */

menuButton.addEventListener("click", function () {
    if (wrapper.classList.contains("menuIsOpen")) {
        wrapper.classList.remove("menuIsOpen");
    } else {
        wrapper.classList.add("menuIsOpen");
    }
})

/* Touch the main content area close the Navigation */

mainContentArea.addEventListener("touchstart", function () {
    if (wrapper.classList.contains("menuIsOpen")) {
        wrapper.classList.remove("menuIsOpen");
    }
})