Last active
January 27, 2018 21:47
-
-
Save jurekbarth/f3c9d4ae9d68ef4c006f0f37fe2f9da6 to your computer and use it in GitHub Desktop.
Intersection Obeserver
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!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