Last active
June 25, 2021 20:35
-
-
Save okikio/6d2a210cc1f55eda1220ae6b6cfd52c6 to your computer and use it in GitHub Desktop.
Parallax Template
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
| <nav class="navbar"> | |
| <div class="container navbar-layout"> | |
| <h4 class="navbar-title">Logo</h4> | |
| <section class="navbar-main"> | |
| <a href="/about">about</a> | |
| <a href="/portfolio">portfolio</a> | |
| <a href="/contact">contact</a> | |
| </section> | |
| </div> | |
| </nav> | |
| <main class="banner hero"> | |
| <article class="container"> | |
| <div class="image-container"> | |
| <div class="overlay"></div> | |
| <img class="effect-parallax" src="https://images.unsplash.com/photo-1598891324044-3f4b30b0d55c?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyNDY0ODQ2MQ&ixlib=rb-1.2.1&q=85" alt="Alternate" loading="lazy" /> | |
| <section class="layout"> | |
| <header class="content"> | |
| <h1>Title</h1> | |
| <h2>Description</h2> | |
| </header> | |
| </section> | |
| </div> | |
| </article> | |
| </main> |
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
| /* Limits a number to a max, and a min value */ | |
| let limit = (v, a, b) => (v > b ? b : v < a ? a : v); | |
| /* Re-maps a number from one range to another. Numbers outside the range are not clamped to 0 and 1, because out-of-range values are often intentional and useful. */ | |
| let scale = (e, t, n, r, i) => r + (i - r) * ((e - t) / (n - t)); | |
| let navHeight = document.querySelector(".navbar").getBoundingClientRect() | |
| .height; | |
| // Initialize images | |
| let banner = document.querySelector(".banner"); | |
| let layout = banner.querySelector(".layout"); | |
| let header = banner.querySelector("h1"); | |
| let main = banner.querySelector("h2"); | |
| let target = banner.querySelector("img"); | |
| let overlay = banner.querySelector(".overlay"); | |
| let isBanner = !banner.classList.contains("hero"); | |
| let boundRect = target.getBoundingClientRect(); | |
| let clientRect = { | |
| height: boundRect.height, | |
| width: boundRect.width, | |
| left: boundRect.left + window.pageXOffset, | |
| top: boundRect.top + window.pageYOffset | |
| }; | |
| let windowWid; | |
| let resize, scroll; | |
| let canScroll = true; | |
| let canResize = true; | |
| window.addEventListener( | |
| "resize", | |
| (resize = () => { | |
| // Prevent layout-thrashing: [wilsonpage.co.uk/preventing-layout-thrashing/] | |
| if (canResize) { | |
| let timer, raf; | |
| canResize = false; | |
| raf = requestAnimationFrame(() => { | |
| windowWid = window.innerWidth; | |
| // On Resize re-scale the parallax effect | |
| let boundRect = target.getBoundingClientRect(); | |
| clientRect = { | |
| height: boundRect.height, | |
| width: boundRect.width, | |
| left: boundRect.left + window.pageXOffset, | |
| top: boundRect.top + window.pageYOffset | |
| }; | |
| // set a timeout to un-throttle | |
| timer = window.setTimeout(() => { | |
| canResize = true; | |
| timer = window.clearTimeout(timer); | |
| raf = window.cancelAnimationFrame(raf); | |
| }, 300); | |
| }); | |
| } | |
| }) | |
| ); | |
| window.addEventListener( | |
| "scroll", | |
| (scroll = () => { | |
| // Prevent layout-thrashing: [wilsonpage.co.uk/preventing-layout-thrashing/] | |
| if (canScroll) { | |
| canScroll = false; | |
| let raf = window.requestAnimationFrame(() => { | |
| let scrollTop = window.scrollY; | |
| // On scroll turn on parallax effect for images with the class "effect-parallax" | |
| if (target && target.classList.contains("effect-parallax")) { | |
| let { top, height } = clientRect; | |
| let topScroll = scrollTop + (isBanner ? navHeight : 0); | |
| let endPt = height + top; | |
| let startPt = top; | |
| // Only compute the parallax effect, if the image is in view | |
| if (topScroll >= startPt && topScroll <= endPt) { | |
| // Convert `value` to a scale of 0 to 1 | |
| let value = scale(topScroll, startPt, endPt, 0, 1); | |
| // Restrict value to a min of 0 and a max of 1 | |
| value = limit(value, 0, 1); | |
| // Animate the translateY value to create the parallax effect | |
| let imgTranslate = scale(value, 0, 0.75, 0, height / 2).toFixed(4); | |
| Object.assign(target.style, { | |
| transform: `translateY(${imgTranslate}px)` | |
| }); | |
| // Animate overlay opacity in tandem with the Parallax effect | |
| let overlayOpacity = scale(value, 0, 0.75, 0.1, 0.8).toFixed(4); | |
| Object.assign(overlay.style, { opacity: overlayOpacity }); | |
| // Play with the opacity value to create the effect of text fading out of view | |
| let mainOpacity = scale(value, 0, 0.45, 1, 0).toFixed(4); | |
| Object.assign(main.style, { opacity: mainOpacity }); | |
| // Change the header color to white as you scroll, so, you can still see the text | |
| let color = scale(value, 0, 0.45, 0, 255).toFixed(4); | |
| Object.assign(header.style, { | |
| color: `rgb(${color}, ${color}, ${color})` | |
| }); | |
| // Move the text in tandem (at a slower rate) with the parallax effect | |
| let layoutTranslate = limit( | |
| scale(value, 0, 1, 0, height / 2), | |
| 0, | |
| height / 3 | |
| ).toFixed(4); | |
| Object.assign(layout.style, { | |
| transform: `translateY(${layoutTranslate}px)` | |
| }); | |
| } | |
| } | |
| canScroll = true; | |
| raf = window.cancelAnimationFrame(raf); | |
| }); | |
| } | |
| }) | |
| ); | |
| resize(); | |
| scroll(); |
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
| body { | |
| height: 250vh; | |
| } | |
| .navbar { | |
| position: relative; | |
| display: block; | |
| height: 60px; | |
| width: 100%; | |
| } | |
| .navbar-layout { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| height: 100%; | |
| } | |
| .navbar-title { | |
| padding-left: 1.5rem; | |
| } | |
| .navbar a { | |
| padding: 1rem 1.5rem; | |
| } | |
| .container { | |
| max-width: 1024px; | |
| width: 100%; | |
| margin: 0 auto; | |
| } | |
| .banner .image-container { | |
| position: relative; | |
| width: 100%; | |
| height: 500px; | |
| overflow: hidden; | |
| } | |
| .banner .overlay { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: #19192d; | |
| opacity: 0.1; | |
| z-index: 10; | |
| } | |
| .banner .layout { | |
| position: absolute; | |
| height: 100%; | |
| display: flex; | |
| align-items: center; | |
| padding: 0 1rem; | |
| z-index: 20; | |
| } | |
| @media (min-width: 700px) { | |
| .banner .layout { | |
| padding: 0 3rem; | |
| } | |
| } | |
| .banner img { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| -o-object-fit: cover; | |
| object-fit: cover; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment