JSFiddle - React, Tailwind, and code Playground
by lupos
HTML
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
<div id="header">
HEADER
</div>
<div id="notTheHeader">
<div id="pushDown">
PUSH DOWN
</div>
<div id="magazineImage">
MAGAZINE IMAGE
</div>
<div id="content" class="noScroll">
<div id="leftRail">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<div id="tabs">TABS</div>
<div class="wrapper">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent at nisi non eros suscipit laoreet a eget lectus. Donec aliquam risus in ante tincidunt fringilla. Nunc ultricies odio nec elementum hendrerit. In tristique quis metus vel tristique. Praesent facilisis bibendum ultrices. Maecenas lectus felis, luctus vel ligula sed, ornare convallis nisl. Vestibulum vitae nulla eros. Aenean ac blandit nulla. Fusce scelerisque ac ipsum quis accumsan. Cras ullamcorper odio id dolor vulputate tristique a nec augue. Fusce suscipit dui id sollicitudin fringilla. Aenean nisi dolor, hendrerit id tellus ut, interdum commodo urna. Nunc auctor augue eget neque elementum dignissim sed bibendum lectus....
SCSS
$headerHeightLarge : 100px;
$headerHeightSmall : 50px;
* {
box-sizing: border-box;
}
body {
float: left;
margin: 0;
height: 100%;
width: 100%;
&.lockScroll{
overflow-y: hidden;
}
>div{
width: 100%;
float: left;
clear: both;
}
}
#header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100px;
z-index: 10;
background: red;
}
#notTheHeader{
float: left;
width: 100%;
margin-top: 100px;
overflow-x: hidden;
overflow-y: auto;
}
#pushDown {
height: 100px;
background: grey;
}
#magazineImage{
height: auto;/*content is an image should keep ratio*/
}
#content {
overflow-x:hidden;
overflow-y: auto;
background: green;
position: relative;
padding-left: 200px;/*same as left rail width*/
&.positioned {
top: 100%;/*top set by js. 100% keeps it off screen till site renders so math can work*/
left: 0;
right: 0;
height: 100%;/*height is set by js as well. if no push down/magazine we can do this with css*/
}
&.noScroll{
#leftRail{
position: absolute;
top: 0;
left: 0;
bottom: 0;
}
}
.wrapper{
max-width: 800px;
}
}
#leftRail {
overflow-x:hidden;
overflow-y: auto;
width: 200px;
background: yellow;
ul{
padding-top: 20px;/*same as tab height - sass magic*/
}
}
#tabs {
position: absolute;
top: 0;
left: 0;
height: 20px;
width: 200px;/*same as rail width*/
background: orange;
}
.stickRail {
#leftRail, #tabs{
position: fixed;
}
#tabs{
top: 100px;
}
}
.noScroll {
overflow-y: hidden !important;
}
#content #leftRail{
position: fixed;
top: 100px;/*header height;*/
left: 0;
height: 100%;
}
ul, li{
width: 100%;
padding:0;
margin:0;
}
li{
border-bottom: 1px solid gray;
list-style: none;
...
JavaScript
var $window = $(window),
$body = $("body"),
$notHeader = $("#notTheHeader"),
$content = $("#content"),
$header = $("#header"),
$leftRail = $("#leftRail"),
mobileSafari = false,
userAgent = window.navigator.userAgent;
if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i)) {
mobileSafari = true;
}
var sizeContent = function(){
var contentHeight,
headerHeight;
headerHeight = $header.outerHeight(true);
contentHeight = $window.height() - headerHeight;//ignore push down and mag image height
if(mobileSafari){
$notHeader.height(contentHeight + 60);
} else {
$notHeader.height(contentHeight);
}
$content.height(contentHeight);
$leftRail.height(contentHeight);//needed for fixed state
//incase the height of the browser is changed keeps body scrolled to bottom
if($content.scrollTop() > 0){
$notHeader.scrollTop($body.height());
}
};
sizeContent()//call once at app start
var checkScroll = function(){
//reached end of window scroll
if (($notHeader.height() + $notHeader.get(0).scrollTop) >= $notHeader.get(0).scrollHeight)
{
//allow content scrol
$content.removeClass("noScroll");
//disable body scroll
$notHeader.addClass("noScroll");
}
//if content has scrolled ensure rail is stuck
if($content.scrollTop() > 0 && !$content.hasClass("stickRail")){
$content.addClass("stickRail");
}
//if content is scrolled to top release rail
//freeze content scroll and enable body scroll
if($content.scrollTop() == 0 && $content.hasClass("stickRail")){
$content.removeClass("stickRail");
$content.addClass("noScroll");
$notHeader.removeClass("noScroll");
}
}
//update content height if window is resized - TODO:throttle
$window.on("resize", function(){
sizeContent();
});
$notHeader.on("scroll", function(e){
checkScroll(e);
});
$("#content").on("scroll",...