-
-
Save kobitoDevelopment/fb90195eaf297c1f83d805335b111690 to your computer and use it in GitHub Desktop.
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
| <div class="parallax"> | |
| <div class="parallax__inner js-parallax"> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| <div class="box"></div> | |
| </div> | |
| </div> | |
| <div class="parallax-end"></div> |
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
| /* スクロールアニメーションを設定 */ | |
| // スクロール率を取得 | |
| let scrollPercent = 0; | |
| let animationID; | |
| // 線形補完 第一引数:開始時 第二引数:終了時 第三引数:上限 | |
| function lerp(x, y, a) { | |
| return (1 - a) * x + a * y; | |
| } | |
| function scalePercent(start, end) { | |
| return (scrollPercent - start) / (end - start); | |
| } | |
| // アニメーション配列を設定 | |
| const animationScripts = []; | |
| animationScripts.push( | |
| { | |
| start: 0, // アニメーションが開始される位置 | |
| end: 10, // アニメーションが終了する位置 | |
| function() { | |
| parallaxContent.scrollTo({ | |
| left: 0, | |
| }); | |
| }, | |
| }, | |
| { | |
| start: 10, // アニメーションが開始される位置 | |
| end: 90, // アニメーションが終了する位置 | |
| function() { | |
| parallaxContent.scrollTo({ | |
| left: lerp(0, parallaxContentWidth - windowWidth, scalePercent(this.start, this.end)), | |
| }); | |
| }, | |
| }, | |
| { | |
| start: 90, // アニメーションが開始される位置 | |
| end: 100, // アニメーションが終了する位置 | |
| function() { | |
| parallaxContent.scrollTo({ | |
| left: parallaxContentWidth - windowWidth, | |
| }); | |
| }, | |
| } | |
| ); | |
| // アニメーション関数を設定 | |
| function playScrollAnimation() { | |
| animationScripts.forEach(function (animation) { | |
| if (scrollPercent >= animation.start && scrollPercent <= animation.end) { | |
| animation.function(); | |
| } | |
| }); | |
| } | |
| // | |
| const parallax = document.querySelector(".parallax"); | |
| const parallaxContent = document.querySelector(".js-parallax"); | |
| const parallaxEnd = document.querySelector(".parallax-end"); | |
| let scrollHeight; | |
| const clientHeight = document.documentElement.clientHeight; // デバイス表示領域の高さを取得 | |
| let windowHeight; | |
| let windowWidth; | |
| let isIntersecting; | |
| let setScrollTop; | |
| let windowBottom; | |
| let parallaxRect; | |
| let parallaxTop; | |
| let parallaxEndRect; | |
| let parallaxEndTop; | |
| let parallaxContentWidth; | |
| function setSize() { | |
| windowHeight = window.innerHeight; | |
| windowWidth = window.innerWidth; | |
| setScrollTop = window.pageYOffset || document.documentElement.scrollTop; | |
| parallaxRect = parallax.getBoundingClientRect(); | |
| parallaxTop = parallaxRect.top + setScrollTop; | |
| parallaxEndRect = parallaxEnd.getBoundingClientRect(); | |
| parallaxEndTop = parallaxEndRect.top + setScrollTop; | |
| parallaxContentWidth = parallaxContent.scrollWidth; // 画面から溢れたコンテンツの長さも取得 | |
| parallax.style.height = parallaxContentWidth - windowWidth + "px"; | |
| } | |
| window.addEventListener("load", function () { | |
| setSize(); | |
| scrollHeight = parallax.offsetHeight; // パララックス要素の総スクロール量を取得 | |
| parallaxEndRect = parallaxEnd.getBoundingClientRect(); | |
| parallaxEndTop = parallaxEndRect.top + setScrollTop; | |
| }); | |
| window.addEventListener("resize", function () { | |
| setSize(); | |
| scrollHeight = parallax.offsetHeight; // パララックス要素の総スクロール量を取得 | |
| parallaxEndRect = parallaxEnd.getBoundingClientRect(); | |
| parallaxEndTop = parallaxEndRect.top + setScrollTop; | |
| }); | |
| /* パララックス要素が画面内にある場合のみスクロールイベントを発火 開始 */ | |
| const observer = new IntersectionObserver(function (entries) { | |
| entries.forEach(function (entry) { | |
| if (entry.isIntersecting) { | |
| window.addEventListener("scroll", parallaxAction, { passive: true }); | |
| //画面内判定フラグ | |
| isIntersecting = true; | |
| } else { | |
| window.removeEventListener("scroll", parallaxAction, { passive: true }); | |
| //画面内判定フラグ | |
| isIntersecting = false; | |
| } | |
| }); | |
| }); | |
| //observer監視開始 | |
| observer.observe(parallax); | |
| /* パララックス要素が画面内にある場合のみスクロールイベントを発火 終了 */ | |
| function parallaxAction() { | |
| setSize(); | |
| scrollHeight = parallax.offsetHeight; // パララックス要素の総スクロール量を取得 | |
| parallaxEndRect = parallaxEnd.getBoundingClientRect(); | |
| parallaxEndTop = parallaxEndRect.top + setScrollTop; | |
| const scrollTop = window.pageYOffset || document.documentElement.scrollTop; | |
| const scrollDif = scrollTop - parallaxTop; // スクロール量をアニメーション数値に利用したい場合に使用 | |
| scrollPercent = (scrollDif / (scrollHeight - clientHeight)) * 100; // 何%スクロールしているかを算出 | |
| windowBottom = scrollTop + windowHeight; | |
| const controlClass = parallaxContent.classList; // classの着脱は変数に格納(performance配慮) | |
| /* パララックス要素1つ目 */ | |
| if (scrollTop > parallaxTop && windowBottom > parallaxEndTop) { | |
| parallaxContent.scrollTo({ | |
| left: parallaxContentWidth - windowWidth, | |
| }); | |
| } else { | |
| // パララックス開始位置を通過した場合 | |
| if (scrollTop > parallaxTop) { | |
| playScrollAnimation(); | |
| } else { | |
| // パララックス開始位置に到達する前 | |
| parallaxContent.scrollTo({ | |
| left: 0, | |
| }); | |
| } | |
| } | |
| } |
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 { | |
| padding-top: 50vh; | |
| padding-bottom: 600px; | |
| } | |
| .parallax { | |
| position: relative; | |
| height: 100vh; // 希望の固定し続けたい高さ | |
| width: 100%; | |
| &__inner { | |
| position: sticky; | |
| top: 0; | |
| left: 0; | |
| height: 100vh; | |
| width: 100%; | |
| background: green; // デバッグ用背景 | |
| display: flex; | |
| align-items: center; | |
| gap: 6%; | |
| overflow-x: auto; | |
| -ms-overflow-style: none; //スクロールバー非表示 IE/Edgeへ対応 | |
| scrollbar-width: none; //スクロールバー非表示 firefoxへ対応 | |
| &::-webkit-scrollbar { | |
| display: none; //スクロールバー非表示 safari/chromeへ対応 | |
| } | |
| .box { | |
| width: 30%; // デバッグ用boxサイズ | |
| aspect-ratio: 1; // デバッグ用boxサイズ | |
| flex-shrink: 0; | |
| // デバッグ用 | |
| font-size: 240px; | |
| color: white; | |
| border: 4px solid #fff; // デバッグ用boxスタイル | |
| &:focus { | |
| border-color: red; | |
| } | |
| } | |
| } | |
| } | |
| /*デバッグ用*/ | |
| .parallax-end { | |
| margin-bottom: 50vh; | |
| } | |
| /*デバッグ用*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment