Skip to content

Instantly share code, notes, and snippets.

@jurekbarth
Last active January 27, 2018 21:47
Show Gist options
  • Save jurekbarth/f3c9d4ae9d68ef4c006f0f37fe2f9da6 to your computer and use it in GitHub Desktop.
Save jurekbarth/f3c9d4ae9d68ef4c006f0f37fe2f9da6 to your computer and use it in GitHub Desktop.
Intersection Obeserver
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
box-sizing: border-box;
}
body {
width: 100%;
height: auto;
background-color: #f1f3f5;
}
.page-wrapper {
postion: relative;
padding-left: 200px;
}
.menu {
position: fixed;
top: 0;
left: 0;
width: 200px;
height: 100%;
border-right: 1px solid #adb5bd;
}
.section {
height: 500px;
width: 100%;
padding: 1em;
}
.section.active {
color: white;
}
.section:nth-of-type(1) {
background: #b197fc;
}
.section:nth-of-type(2) {
background: #91a7ff;
}
.section:nth-of-type(3) {
background: #74c0fc;
}
.section:nth-of-type(4) {
background: #66d9e8;
}
.section:nth-of-type(5) {
background: #63e6be;
}
</style>
</head>
<body>
<div class="page-wrapper">
<div class="menu">
<ul>
<li>
<a href="#s1">Section 1</a>
</li>
<li>
<a href="#s2">Section 2</a>
</li>
<li>
<a href="#s3">Section 3</a>
</li>
<li>
<a href="#s4">Section 4</a>
</li>
<li>
<a href="#s5">Section 5</a>
</li>
</ul>
</div>
<div id="contents" class="contents">
<div id="s1" class="section">
<h1>Section 1</h1>
</div>
<div id="s2" class="section">
<h1>Section 2</h1>
</div>
<div id="s3" class="section">
<h1>Section 3</h1>
</div>
<div id="s4" class="section">
<h1>Section 4</h1>
</div>
<div id="s5" class="section">
<h1>Section 5</h1>
</div>
</div>
</div>
<script>
const sections = [].slice.call(document.querySelectorAll(".section"));
function createObserver(el) {
let observer;
const options = {
root: null,
rootMargin: "0px",
threshold: 0.5
};
observer = new IntersectionObserver(handleIntersect, options);
observer.observe(el);
}
function handleIntersect(entries, observer) {
entries.forEach((entry) => {
let box = entry.target;
let visible = entry.intersectionRatio;
if (visible > 0.5) {
box.classList.add('active');
} else {
box.classList.remove('active');
}
});
}
const setup = (sections) => {
for (let i in sections) {
const el = sections[i];
createObserver(el);
}
}
setup(sections);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Simple JS</title>
<style>
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
body {
width: 100%;
height: auto;
background-color: #f1f3f5;
}
.page-wrapper {
postion: relative;
padding-left: 200px;
}
.menu {
position: fixed;
top: 0;
left: 0;
width: 200px;
height: 100%;
border-right: 1px solid #adb5bd;
}
.section {
height: 75vh;
width: 100%;
padding: 1em;
}
.section.active {
color: white;
}
.section:nth-of-type(1) {
background: #b197fc;
}
.section:nth-of-type(2) {
background: #91a7ff;
}
.section:nth-of-type(3) {
background: #74c0fc;
}
.section:nth-of-type(4) {
background: #66d9e8;
}
.section:nth-of-type(5) {
background: #63e6be;
}
.marker {
width: 100%;
top: 50%;
position: fixed;
border-bottom: 5px dotted #e03131;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
</style>
</head>
<body>
<div class="page-wrapper">
<div class="menu">
<ul>
<li>
<a href="#s1">Section 1</a>
</li>
<li>
<a href="#s2">Section 2</a>
</li>
<li>
<a href="#s3">Section 3</a>
</li>
<li>
<a href="#s4">Section 4</a>
</li>
<li>
<a href="#s5">Section 5</a>
</li>
</ul>
</div>
<div id="contents" class="contents">
<div id="s1" class="section">
<h1>Section 1</h1>
</div>
<div id="s2" class="section">
<h1>Section 2</h1>
</div>
<div id="s3" class="section">
<h1>Section 3</h1>
</div>
<div id="s4" class="section">
<h1>Section 4</h1>
</div>
<div id="s5" class="section">
<h1>Section 5</h1>
</div>
</div>
</div>
<div id="marker" class="marker">
</div>
<script>
const sections = [].slice.call(document.querySelectorAll(".section"));
const positions = [];
// just to understand
const marker = document.getElementById("marker");
// initial window height
let windowHeight = window.innerHeight;
let activeElement = sections[0];
const makeActive = (el) => {
activeElement.classList.remove('active');
el.classList.add('active');
activeElement = el;
}
// throttle a litte bit
const throttle = (func, delay) => {
let time = Date.now();
return function () {
if (time + delay - Date.now() < 0) {
func();
time = Date.now();
}
};
};
// scroll event
const se = () => {
// get offset
const offset = window.pageYOffset;
// get "middle" of window
const mark = offset + (windowHeight / 2);
// add to marker, just for the demo
marker.innerHTML = mark;
// mark whatever should be active
for (let i of positions) {
// each element has a range where it's active y-position and the bottom of the element y + height
if (i.y < mark && (i.y + i.height) > mark) {
// get the corresponding element
const el = sections[i.i];
// make it active
makeActive(el);
// break, no need to go further
break;
}
}
};
// setup
const setup = () => {
windowHeight = window.innerHeight;
for (let i in sections) {
const el = sections[i];
const { y, height } = el.getBoundingClientRect();
positions.push({ y, height, i });
}
marker.innerHTML = (windowHeight / 2);
se();
};
setup();
window.addEventListener("resize", setup);
window.addEventListener("scroll", throttle(se, 10));
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment