<!-- <div class="fixed"></div> -->

<div class="container">
	<ul class="section one is-released">
		<li>panel</li>
		<li>content</li>
		<li>content</li>
		<li>content</li>
		<li>content</li>
		<li>content</li>
	</ul>
	<div class="section two">
		<div class="content">panel</div>
	</div>
	<div class="section three">
		<div class="content">panel</div>
	</div>
	<div class="section four">
		<div class="content">panel</div>
	</div>
	<div class="section five">
		<div class="content">panel</div>
	</div>
</div>
body{
	margin: 0;
	padding: 0;
}

.fixed{
	position: fixed;
	z-index: 0;
	top: 0;
	left: 0;
	width: 100%;
	height: 200px;
	background-image: url(https://images.unsplash.com/photo-1500122710449-d384ebf0891a?ixlib=rb-0.3.5&q=85&fm=jpg&crop=entropy&cs=srgb&s=1df2a3596d28b4e9559c4feed0cedf41);
}

*{box-sizing: border-box;}

.container{
	transition: 300ms ease ;
}

.section{
	width: 100%;
	position: fixed;
	box-shadow: inset 0 0 0 5px ghostwhite;
	min-height: 600px;
	color: white;
	list-style: none;
	padding: 25px;
}
.is-released{
	position: relative!important;
}
View Compiled
// UI pattern I'm working on for a client project. Thought I'd share :)
// Gonna be porting this over to a react component in the near future, so be on the lookout for that
// Still working on this, but here's a plain ol javascript way of having a fun fixed-then-scrolling panel ui
// Far as I can tell, this works in Safari, Chrome, Firefox
/* Pretty mobile friendly, too. Only problem is fixed position bug when scrolling in a mobile
browser and the window shrinks, but the panels don't resize accordingly. I'm looking at window 
resize handler to see if that can alleviate the problem. 🎉
*/

var colors=['rebeccapurple','blanchedalmond','mistyrose','goldenrod','dodgerblue','palegoldenrod']
var container = document.querySelector('.container')
var currentIndex = 0
var activePanel = null
var config ={
	scrollItems:[],
	container:null,
	children: null,
	lastScrollTop:0,
	direction: 'down'
}
var createScrollSystem = function(accumulator, node) {
	if(node){
		var children = node.children
		for(var i=children.length-1; i>=0; i--){
			var height = children[i].getBoundingClientRect().height
			accumulator=accumulator+height+Math.ceil(window.innerHeight*.75 - (i*-50) )
			var scrollItem = {
					height: Math.ceil(height)
				, scrollHeight: Math.ceil(accumulator)
				, spaceFromTop: Math.ceil(window.innerHeight*.75 - (-i*-50) )
			}
			config.scrollItems.push(scrollItem)
			children[i].style.top=`${scrollItem.spaceFromTop}px`
			children[i].style.marginBottom=`${scrollItem.spaceFromTop}px`
			children[i].style.zIndex=-i+10
			children[i].style.backgroundColor=colors[i]
		}
		node.style.height=`${Math.ceil(config.scrollItems[config.scrollItems.length-1].scrollHeight+window.innerHeight)}px`
		config.container=node
		config.children=children
		activePanel=config.children[0]
	}
}

createScrollSystem(0,container)

function handleScroll(e){
	
	var length = config.children.length-1

	//handle scroll direction
	var s=window.scrollY
	if(s < config.lastScrollTop){config.direction='up'}
	else{config.direction='down'}
	config.lastScrollTop=s

	//handle panel behavior while user scrolls DOWN the page
	if(config.direction==='down'){
		var scrollIndex=0
			scrollIndex=currentIndex
			if(
			scrollIndex < length &&
			config.children[scrollIndex] === activePanel &&
			config.children[scrollIndex].getBoundingClientRect().bottom <= 0 ){
				scrollIndex+=1
				config.children[scrollIndex].classList.add('is-released')
				currentIndex=scrollIndex
				activePanel=config.children[currentIndex]
			}
	}

	//handle panel behavior while user scrolls UP the page
	if(config.direction==='up'){
		scrollIndex=currentIndex
			if(
				scrollIndex > 0 &&
				currentIndex > 0 &&
				config.children[scrollIndex] === activePanel &&
				config.children[scrollIndex].getBoundingClientRect().top - config.scrollItems[length - scrollIndex].spaceFromTop >= 0 ){
					config.children[scrollIndex].classList.remove('is-released')
					scrollIndex-=1  
					currentIndex=scrollIndex
					activePanel=config.children[currentIndex]
			}
	}

	//handle background color of container
	container.style.backgroundColor=colors[currentIndex]
	if(config.children[length].getBoundingClientRect().bottom <= 0){container.style.backgroundColor='ghostwhite'}
}

window.addEventListener('scroll', function(e){handleScroll(e)})

/* This down here needs to be cleaned up 👇
============================================ */
// class ScrollItem {
// 	constructor(height, scrollHeight, spaceFromTop) {
// 		this.height = height
// 		this.scrollHeight = scrollHeight
// 		this.spaceFromTop = spaceFromTop
// 	}

// 	newScrollHeight(newHeight){ this.scrollHeight = newHeight }

// }
// const CONTAINER = document.querySelector('.container') //the element holding the panels we want to scroll
// const SCROLL_ITEM_NODES  = Array.from( document.querySelectorAll('.menu-container') ) //make an array from the supplied dom elements
// let scrollItems = [] //array to store our new acrollItems created with SCROLL_ITEM_NODES
// let currentScrollIndex = 0 //current index of active panel
// let lastScrollTop = 0 //fulcrum to determine scroll direction
// let totalPanelHeight = 0 //height of all panels passed into the view
// let createScrollSystem = null //store a null value for our function to create scrollItems
// let topSpace = null

// //Ok, let's get down to business:

// // 1. here's our function to generate the ScrollItems
// // we're going to use this function when the page loads, then re-use it if the user updates the page height
// createScrollSystem = function(accumulator, nodes, arr) {
// 	for(let i in nodes){
// 		let height = nodes[i].getBoundingClientRect().height
// 		let width = nodes[i].getBoundingClientRect().width
// 		accumulator=accumulator+height+Math.ceil(window.innerHeight*.5 - (i*-40) )
// 		let scrollItem = new ScrollItem(
// 			Math.ceil(height),
// 			Math.ceil(accumulator),
// 			Math.ceil(window.innerHeight*.5 - (i*-40) )
// 		)
// 		arr.push(scrollItem)
// 		nodes[i].style.paddingTop=`${scrollItem.spaceFromTop}px`
// 	}
// 	CONTAINER.style.height=`${Math.ceil(scrollItems[scrollItems.length-1].scrollHeight+window.innerHeight)}px`
// 	return arr
// }

// // 2. let's make those ScrollItems
// createScrollSystem(0,SCROLL_ITEM_NODES,scrollItems)
// // console.log(scrollItems)
// // console.log('CONTAINER style height: ',CONTAINER.style.height)
// console.log(document.body.clientHeight)

// // 4. and let's make sure our objects stay in the right place if the user resizes the window
// let initialWindowHeight = window.innerHeight
// let initialWindowWidth = window.innerWidth
// function resizeWindow(e){
// 	let height = window.innerHeight
// 	let width = window.innerWidth
// 	if(height > initialWindowHeight || height < initialWindowHeight) {
// 		createScrollSystem(0,SCROLL_ITEM_NODES,scrollItems)
// 		// console.log('CONTAINER height: ',CONTAINER.style.height, 'scroll height: ',document.documentElement.scrollHeight)
// 	}
// 	if(width > initialWindowWidth || width < initialWindowWidth) {
// 		// console.log("we're changing the width of the window")
// 	}
// 	// set the initial window values to the new values
// 	initialWindowHeight = window.innerHeight
// 	initialWindowWidth = window.innerWidth
// }

// // 5. now let's do some stuff when the user scrolls the page
// currentScrollIndex = 0
// SCROLL_ITEM_NODES[currentScrollIndex].classList.add('is-released')
// function scrollPanels(e) {
// 	let scrollDistance = window.pageYOffset || document.documentElement.scrollTop
// 	console.log( Math.ceil(scrollDistance) + window.innerHeight, Math.ceil( CONTAINER.getBoundingClientRect().height ) )
// 	// console.log( Math.ceil( CONTAINER.getBoundingClientRect().height ) - Math.ceil(st) )
// 	// if(st>scrollItems[0].scrollHeight){console.log('0 is outta view')}
// 	// if(st>scrollItems[1].scrollHeight){console.log('1 is outta view')}
// 	// if(st>scrollItems[2].scrollHeight){console.log('2 is outta view')}
// 	console.log(scrollItems[0].scrollHeight)
	
// 	// if (st > lastScrollTop){console.log()}
// 	// else {console.log()}
// 	// lastScrollTop = st //update lastScrollTop so we know which direction we're scrolling when the user changes directions
// }





// window.addEventListener('scroll', _.throttle(scrollPanels, 100), false);
// window.addEventListener('resize', _.throttle(resizeWindow, 1000), false);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js