Desktop layout prototype

Requirement: 1. (left) sidebar nav is sticky 2. header is fixed in the top 3. footer has the "uncover the black bit by scrolling up" 4. page-content-overlay for covering the main and footer (Tested in IE11/Chrome/Firefox/Safari)

by junhui

HTML

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Desktop Layout Prototype</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <div class="wrapper">
        <nav>
            Sidebar navigation (sticky)
            <br />
            <button id="page-content-overlay-trigger">Toogle the page-content-overlay</button>
            <br /> Menu Item
            <br /> Menu Item
            <br /> Menu Item
            <br /> Menu Item
            <br /> Menu Item
            <br /> Menu Item
            <br /> Menu Item
            <br /> Menu Item
            <br /> Menu Item
            <br /> Menu Item
            <br /> Menu Item
        </nav>
        <header>
            Header (fixed)
        </header>
        <main>
            START
            <br /> Lorem ipsum dolor sit, amet consectetur adipisicing elit. In nisi nihil commodi odit iure rerum eveniet non
            enim deleniti ipsam esse reprehenderit neque, nostrum voluptate exercitationem suscipit? Repellat consectetur
            iure magnam porro similique possimus expedita quas tempora! Magnam voluptate voluptatum inventore aliquam amet
            pariatur accusamus, iusto repudiandae ab nobis aperiam! Nesciunt nemo ullam iste quasi veritatis numquam, magnam
            odio consectetur quia exercitationem dolor quae amet quibusdam laudantium veniam suscipit sint vel est doloremque
            totam laborum voluptates quidem aliquam! A architecto, consequatur dolores minus porro quae? Officia reprehenderit
            iste eius pariatur labore quod dolore eum omnis, error illo totam ducimus hic qui accusamus, quidem enim doloribus
            fugit atque vitae, minus ratione provident exercitationem incidunt. Et, nemo optio. Ab esse distinctio dolor
            tempore placeat, eligendi natus nobis quod ipsum reprehenderit ducimus iusto nostrum exercitationem iure facilis
...

CSS

/* 
 * Requirement:
 *   1. (left) sidebar nav is sticky
 *   2. header is fixed in the top
 *   3. footer has the "uncover the black bit by scrolling up"
 *   4. page-content-overlay for covering the main and footer
 *
 * The HTML elements' hierarchy:
 * * root
 *   * .wrapper (relative)
 *     * nav (fixed, z-index: 1)
 *     * header (fixed, z-index: 1)
 *     * main
 *     * footer
 *       * .footer-top
 *       * .footer-bottom (fixed, z-index: -1)
 *     * .page-content-overlay (fixed: z-index: auto)
 *
 * And the stacking context hierarchy:
 * * root stacking context  
 *   * nav (fixed, z-index: 1)
 *   * header (fixed, z-index: 1)
 *   * .page-content-overlay (fixed, z-index: auto)
 *   * main, footer, .footer-top
 *   * .footer-bottom (fixed, z-index: -1)
 *  
 * Read more about stacking context:
 * https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
 */

.wrapper {
  position: relative;
}

/* 
 * nav is fixed by default, when scrolling to the bottom, it turns to
 * absolute for sticking above the footer (this done by Javascript).
 */

nav {
  position: fixed;
  top: 80px; /* top matches the fixed height of the header */

  width: 240px; /* fixed width, this matches the main's margin-left */
  /* flexible height that rely on the viewpoint and the header height */
  min-height: calc(100vh - 80px);
  overflow: hidden;

  /* 
   * a large enough vaule that makes sure the nav won't be covered
   * by the page-content-overlay
   */
  z-index: 1;
}

/* header always fixed in top */

header {
  position: fixed;
  top: 0;

  width: 100%; /* full width */

  /* 
   * fixed height, this matches: 
   *   1. the nav's top
   *   2. the nav's min-height
   *   3. the main's margin-top
   *   4. the main's min-height
   */
  height: 80px;

  /* 
   * a large enough vaule that makes sure the header won't be covered
   * by the page-content-overlay
   */
  z-index: 1;
}

/* main */

main {
  /* 
   * This makes...

JavaScript

// Makes the sidebar nav sticky.
window.addEventListener("scroll", stickySidebarNavOnScrll)

var nav = document.querySelector("nav");

var mainHeight = document.querySelector("main").offsetHeight;
var headerHeight = document.querySelector("header").offsetHeight;
var footerTopHeight = document.querySelector(".footer-top").offsetHeight;

function stickySidebarNavOnScrll() {
    var screenHeight = screenSize()[1];
    var scrollTop = pageOffset()[1];

    var offset = scrollTop + screenHeight - headerHeight - mainHeight

    // Use element's style property to pass the CSP style-src policy.
    //
    // > However, styles properties that are set directly on the element's
    // style property will not be blocked, allowing users to safely
    // manipulate styles via Javascript:
    // 
    // Read more: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src#Violation_cases
    if (offset > 0) {
        nav.style.top = "calc(100% - " + nav.offsetHeight + "px - " + footerTopHeight + "px)"
        nav.style.position = "absolute"
    } else {
        nav.style.top = ""
        nav.style.position = ""
    }
}

// page-content-overlay trigger demo
var contentOverlayTigger = document.querySelector("#page-content-overlay-trigger");
var contentOverlay = document.querySelector(".page-content-overlay");

contentOverlayTigger.addEventListener("click", function () {
    if (!contentOverlay.classList.contains("open")) {
        contentOverlay.classList.add("open");
    } else {
        contentOverlay.classList.remove("open");
    }
})
///////////////////////////////
// Helpers

// Cross-browser method for detecting the scrollTop of the
// browser window:
// https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes
function pageOffset() {
    var supportPageOffset = window.pageXOffset !== undefined;
    var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");

    var x = supportPageOffset ? window.pageXOffset :...