Intersection Observer

Example of having an element changing from header to ribbon on scroll with intersectionObserver.

by Travis Almand

HTML

<div id="secondary_wrapper">
	<div id="secondary">
		<div id="profile" class="scrolled"></div>
	</div>
</div>
<div id="primary_wrapper">
	<div id="primary">
		<div id="logo"></div>
		<div id="promo"></div>
	</div>
</div>

<main></main>

CSS

body,
html {
	margin: 0;
	padding: 0;
}

#secondary_wrapper {
	background-color: gray;
	height: 40px;
	position: fixed;
	width: 100%;
}
#primary_wrapper {
	background-color: gainsboro;
}

#secondary {
	background-color: gray;
	height: 40px;
	left: 0;
	margin: auto;
	position: fixed;
	right: 0;
	width: 75%;
	z-index: 2;
}
#profile {
	background-color: rebeccapurple;
	height: 40px;
	position: absolute;
	right: 0;
	width: 120px;
	z-index: 5;
}
#profile.scrolled {
	height: 50px;
}

#primary {
	align-items: center;
	background-color: gainsboro;
	display: flex;
	height: 80px;
	margin: auto;
	padding-top: 40px;
	width: 75%;
}
#logo {
	border: 1px solid gray;
	height: 50px;
	width: 120px;
}
#promo {
	flex-grow: 1;
}

main {
	height: 2000px;
}

JavaScript

console.clear();

var profile = document.querySelector('#profile');
var secondary = document.querySelector('#secondary');
var primary = document.querySelector('#primary');

var top = (primary.offsetHeight - profile.offsetHeight) / 2 + 20;

var callback = function (entries, observer) {
	var clientRectY = entries[0].boundingClientRect.y;
	
	profile.classList.toggle('scrolled', clientRectY >= 0);
	
	if (profile.classList.contains('scrolled')) {
		profile.style.top = top + 'px';
	} else {
		profile.style.top = '0px';
	}
}

var options = {
	root: null,
	rootMargin: '0px',
	threshold: 1.0
}

var observer = new IntersectionObserver(callback, options);

var target = document.querySelector('#primary');
observer.observe(target);

window.setTimeout(function () {
	profile.style.transition = 'all 0.25s';
}, 100);