WEBLEB
Home
Editor
Login
Pro
English
English
Français
Español
Português
Deutsch
Italiano
हिंदी
Animated Continuous Sections with GSAP Observer
1041
Andev.web
Open In Editor
Publish Your Code
Recommended
11 August 2025
HTML Template with P5.js and CSS
2 March 2025
HTML, Login Register animated
28 November 2024
Matrix Animated Background
HTML
Copy
Andev Web
Scroll down
Animated with GSAP
GreenSock
Animation platform
Keep scrolling
CSS
Copy
@import url("https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Cormorant+Garamond&display=swap"); * { box-sizing: border-box; user-select: none; } a { color: #fff; text-decoration: none; } body { margin: 0; padding: 0; height: 100vh; color: white; background: black; font-family: "Cormorant Garamond", serif; text-transform: uppercase; } h2 { font-size: clamp(1rem, 5vw, 5rem); font-weight: 400; text-align: center; letter-spacing: 0.5em; margin-right: -0.5em; color: #cccccc; width: 90vw; max-width: 1200px; } header { position: fixed; display: flex; align-items: center; justify-content: space-between; padding: 0 5%; width: 100%; z-index: 3; height: 7em; font-family: "Bebas Neue", sans-serif; font-size: clamp(0.66rem, 2vw, 1rem); letter-spacing: 0.5em; } section { height: 100%; width: 100%; top: 0; position: fixed; visibility: hidden; } section .outer, section .inner { width: 100%; height: 100%; overflow-y: hidden; } section .bg { display: flex; align-items: center; justify-content: center; position: absolute; height: 100%; width: 100%; top: 0; background-size: cover; background-position: center; } section .bg h2 { z-index: 2; } section .bg .clip-text { overflow: hidden; } .first .bg { background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.3) 100%), url(https://images.unsplash.com/photo-1617478755490-e21232a5eeaf?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYxNzU1NjM5NA&ixlib=rb-1.2.1&q=75&w=1920); } .second .bg { background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.3) 100%), url("https://images.unsplash.com/photo-1617128734662-66da6c1d3505?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYxNzc3NTM3MA&ixlib=rb-1.2.1&q=75&w=1920"); } .third .bg { background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.3) 100%), url(https://images.unsplash.com/photo-1617438817509-70e91ad264a5?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYxNzU2MDk4Mg&ixlib=rb-1.2.1&q=75&w=1920); } .fourth .bg { background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.3) 100%), url(https://images.unsplash.com/photo-1617412327653-c29093585207?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYxNzU2MDgzMQ&ixlib=rb-1.2.1&q=75&w=1920); } .fifth .bg { background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.3) 100%), url("https://images.unsplash.com/photo-1617141636403-f511e2d5dc17?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYxODAzMjc4Mw&ixlib=rb-1.2.1&q=75w=1920"); background-position: 50% 45%; } h2 * { will-change: transform; }
JS
Copy
gsap.registerPlugin(Observer); let sections = document.querySelectorAll("section"), images = document.querySelectorAll(".bg"), headings = gsap.utils.toArray(".section-heading"), outerWrappers = gsap.utils.toArray(".outer"), innerWrappers = gsap.utils.toArray(".inner"), splitHeadings = headings.map(heading => new SplitText(heading, { type: "chars,words,lines", linesClass: "clip-text" })), currentIndex = -1, wrap = gsap.utils.wrap(0, sections.length), animating; gsap.set(outerWrappers, { yPercent: 100 }); gsap.set(innerWrappers, { yPercent: -100 }); function gotoSection(index, direction) { index = wrap(index); // make sure it's valid animating = true; let fromTop = direction === -1, dFactor = fromTop ? -1 : 1, tl = gsap.timeline({ defaults: { duration: 1.25, ease: "power1.inOut" }, onComplete: () => animating = false }); if (currentIndex >= 0) { // The first time this function runs, current is -1 gsap.set(sections[currentIndex], { zIndex: 0 }); tl.to(images[currentIndex], { yPercent: -15 * dFactor }) .set(sections[currentIndex], { autoAlpha: 0 }); } gsap.set(sections[index], { autoAlpha: 1, zIndex: 1 }); tl.fromTo([outerWrappers[index], innerWrappers[index]], { yPercent: i => i ? -100 * dFactor : 100 * dFactor }, { yPercent: 0 }, 0) .fromTo(images[index], { yPercent: 15 * dFactor }, { yPercent: 0 }, 0) .fromTo(splitHeadings[index].chars, { autoAlpha: 0, yPercent: 150 * dFactor }, { autoAlpha: 1, yPercent: 0, duration: 1, ease: "power2", stagger: { each: 0.02, from: "random" } }, 0.2); currentIndex = index; } Observer.create({ type: "wheel,touch,pointer", wheelSpeed: -1, onDown: () => !animating && gotoSection(currentIndex - 1, -1), onUp: () => !animating && gotoSection(currentIndex + 1, 1), tolerance: 10, preventDefault: true }); gotoSection(0, 1);