Anonymous
Невозможно выполнить код анимации прокрутки
Сообщение
Anonymous » 26 ноя 2025, 06:11
Заранее спасибо за помощь. Хоть убей, я не могу выполнить конкретную анимацию прокрутки, использующую gsap и lenis.
Я собрал код в меру своих возможностей:
https://codepen.io/Charles-Kent/pen/XJdZRWy
Код: Выделить всё
RedoMedia Split-Card Scroll Animation | Codegrid
Every idea begins as a single image
Three pillars with one purpose
[img]https://www.charlesthedesigner.com/images/card-images/card_cover_1.jpg[/img]
( 01 )
Interactive Web Experiences
[img]https://www.charlesthedesigner.com/images/card-images/card_cover_2.jpg[/img]
( 02 )
Thoughtful Design Language
[img]https://www.charlesthedesigner.com/images/card-images/card_cover_3.jpg[/img]
( 03 )
Visual Design Systems
Every transition leaves a trace
Код: Выделить всё
@import url("https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&display=swap");
:root {
--bg: #0f0f0f;
--fg: #fff;
--card-1: #b2b2b2;
--card-2: #ce2017;
--card-3: #2f2f2f;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Instrument Serif", sans-serif;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
h1 {
font-size: 4rem;
font-weight: 500;
line-height: 1;
}
p {
font-size: 2rem;
font-weight: 500;
line-height: 1;
}
section {
position: relative;
width: 100%;
height: 100svh;
padding: 2rem;
background-color: var(--bg);
color: var(--fg);
}
.intro,
.outro {
text-align: center;
align-content: center;
}
.intro h1,
.outro h1 {
width: 30%;
margin: 0 auto;
}
.sticky {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.sticky-header {
position: absolute;
top: 20%;
left: 50%;
transform: translate(-50%, -50%);
}
.sticky-header h1 {
position: relative;
text-align: center;
will-change: transform, opacity;
transform: translateY(40px);
opacity: 0;
}
.card-container {
position: relative;
width: 75%;
display: flex;
perspective: 1000px;
transform: translateY(40px);
will-change: width;
}
.card {
position: relative;
flex: 1;
aspect-ratio: 5/7;
transform-style: preserve-3d;
transform-origin: top;
}
#card-1 {
border-radius: 20px 0 0 20px;
}
#card-3 {
border-radius: 0 20px 20px 0;
}
.card-front,
.card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: inherit;
overflow: hidden;
}
.card-back {
display: flex;
justify-content: center;
align-items: center;
text-align: center;
transform: rotateY(180deg);
padding: 2rem;
}
.card-back span {
position: absolute;
top: 2rem;
left: 2rem;
opacity: 0.4;
}
#card-1 .card-back {
background-color: var(--card-1);
color: var(--bg);
}
#card-2 .card-back {
background-color: var(--card-2);
}
#card-3 .card-back {
background-color: var(--card-3);
}
@media (max-width: 1000px) {
h1 {
font-size: 3rem;
}
.intro h1,
.outro h1 {
width: 100%;
}
.sticky {
height: max-content;
padding: 4rem 2rem;
flex-direction: column;
}
.sticky-header {
position: relative;
top: 0;
left: 0;
transform: none;
margin-bottom: 4rem;
}
.sticky-header h1 {
opacity: 1;
}
.card-container {
width: 100%;
flex-direction: column;
gap: 2rem;
}
.card {
width: 100%;
max-width: 400px;
margin: 0 auto;
border-radius: 20px !important;
}
#card-1,
#card-2,
#card-3,
.card-back {
transform: none;
}
}
Код: Выделить всё
import { gsap } from 'https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js';
import { ScrollTrigger } from 'https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js';
import { Lenis } from 'https://unpkg.com/lenis@1.1.5/dist/lenis.min.js';
document.addEventListener("DOMContentLoaded", () => {
gsap.registerPlugin(ScrollTrigger);
const lenis = new Lenis();
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => {
lenis.raf(time * 1000);
});
gsap.ticker.lagSmoothing(0);
const cardContainer = document.querySelector(".card-container");
const stickyHeader = document.querySelector(".sticky-header h1");
let isGapAnimationCompleted = false;
let isFlipAnimationCompleted = false;
function initAnimations() {
ScrollTrigger.getAll().forEach((trigger) => trigger.kill());
const mm = gsap.matchMedia();
mm.add("(max-width: 999px)", () => {
document
.querySelectorAll(".card, .card-container, .sticky-header h1")
.forEach((el) => (el.style = ""));
return {};
});
mm.add("(min-width: 1000px)", () => {
ScrollTrigger.create({
trigger: ".sticky",
start: "top top",
end: `+=${window.innerHeight * 4}px`,
scrub: 1,
pin: true,
pinSpacing: true,
onUpdate: (self) => {
const progress = self.progress;
if (progress >= 0.1 && progress 0.25) {
gsap.set(stickyHeader, {
y: 0,
opacity: 1,
});
}
if (progress = 0.35 && !isGapAnimationCompleted) {
gsap.to(cardContainer, {
gap: "20px",
duration: 0.5,
ease: "power3.out",
});
gsap.to(["#card-1", "#card-2", "#card-3"], {
borderRadius: "20px",
duration: 0.5,
ease: "power3.out",
});
isGapAnimationCompleted = true;
} else if (progress < 0.35 && isGapAnimationCompleted) {
gsap.to(cardContainer, {
gap: "0px",
duration: 0.5,
ease: "power3.out",
});
gsap.to("#card-1", {
borderRadius: "20px 0 0 20px",
duration: 0.5,
ease: "power3.out",
});
gsap.to("#card-2", {
borderRadius: "0px",
duration: 0.5,
ease: "power3.out",
});
gsap.to("#card-3", {
borderRadius: "0 20px 20px 0",
duration: 0.5,
ease: "power3.out",
});
isGapAnimationCompleted = false;
}
if (progress >= 0.7 && !isFlipAnimationCompleted) {
gsap.to(".card", {
rotationY: 180,
duration: 0.75,
ease: "power3.inOut",
stagger: 0.1,
});
gsap.to(["#card-1", "#card-3"], {
y: 30,
rotationZ: (i) => [-15, 15][i],
duration: 0.75,
ease: "power3.inOut",
});
isFlipAnimationCompleted = true;
} else if (progress < 0.7 && isFlipAnimationCompleted) {
gsap.to(".card", {
rotationY: 0,
duration: 0.75,
ease: "power3.inOut",
stagger: -0.1,
});
gsap.to(["#card-1", "#card-3"], {
y: 0,
rotationZ: 0,
duration: 0.75,
ease: "power3.inOut",
});
isFlipAnimationCompleted = false;
}
},
});
return () => {};
});
}
initAnimations();
let resizeTimer;
window.addEventListener("resize", () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
initAnimations();
}, 250);
});
});
Это основано на учебнике CodeGrid, который я нашел на YouTube (который демонстрирует, как должен выглядеть конечный результат):
Выглядит относительно просто, но у меня никак не работает... просто мне повезло, верно? Где у меня код идет не так? Еще раз спасибо.
Подробнее здесь:
https://stackoverflow.com/questions/798 ... to-execute
1764126689
Anonymous
Заранее спасибо за помощь. Хоть убей, я не могу выполнить конкретную анимацию прокрутки, использующую gsap и lenis. Я собрал код в меру своих возможностей: https://codepen.io/Charles-Kent/pen/XJdZRWy [code] RedoMedia Split-Card Scroll Animation | Codegrid Every idea begins as a single image Three pillars with one purpose [img]https://www.charlesthedesigner.com/images/card-images/card_cover_1.jpg[/img] ( 01 ) Interactive Web Experiences [img]https://www.charlesthedesigner.com/images/card-images/card_cover_2.jpg[/img] ( 02 ) Thoughtful Design Language [img]https://www.charlesthedesigner.com/images/card-images/card_cover_3.jpg[/img] ( 03 ) Visual Design Systems Every transition leaves a trace [/code] [code]@import url("https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&display=swap"); :root { --bg: #0f0f0f; --fg: #fff; --card-1: #b2b2b2; --card-2: #ce2017; --card-3: #2f2f2f; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: "Instrument Serif", sans-serif; } img { width: 100%; height: 100%; object-fit: cover; } h1 { font-size: 4rem; font-weight: 500; line-height: 1; } p { font-size: 2rem; font-weight: 500; line-height: 1; } section { position: relative; width: 100%; height: 100svh; padding: 2rem; background-color: var(--bg); color: var(--fg); } .intro, .outro { text-align: center; align-content: center; } .intro h1, .outro h1 { width: 30%; margin: 0 auto; } .sticky { position: relative; display: flex; justify-content: center; align-items: center; } .sticky-header { position: absolute; top: 20%; left: 50%; transform: translate(-50%, -50%); } .sticky-header h1 { position: relative; text-align: center; will-change: transform, opacity; transform: translateY(40px); opacity: 0; } .card-container { position: relative; width: 75%; display: flex; perspective: 1000px; transform: translateY(40px); will-change: width; } .card { position: relative; flex: 1; aspect-ratio: 5/7; transform-style: preserve-3d; transform-origin: top; } #card-1 { border-radius: 20px 0 0 20px; } #card-3 { border-radius: 0 20px 20px 0; } .card-front, .card-back { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; border-radius: inherit; overflow: hidden; } .card-back { display: flex; justify-content: center; align-items: center; text-align: center; transform: rotateY(180deg); padding: 2rem; } .card-back span { position: absolute; top: 2rem; left: 2rem; opacity: 0.4; } #card-1 .card-back { background-color: var(--card-1); color: var(--bg); } #card-2 .card-back { background-color: var(--card-2); } #card-3 .card-back { background-color: var(--card-3); } @media (max-width: 1000px) { h1 { font-size: 3rem; } .intro h1, .outro h1 { width: 100%; } .sticky { height: max-content; padding: 4rem 2rem; flex-direction: column; } .sticky-header { position: relative; top: 0; left: 0; transform: none; margin-bottom: 4rem; } .sticky-header h1 { opacity: 1; } .card-container { width: 100%; flex-direction: column; gap: 2rem; } .card { width: 100%; max-width: 400px; margin: 0 auto; border-radius: 20px !important; } #card-1, #card-2, #card-3, .card-back { transform: none; } } [/code] [code]import { gsap } from 'https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js'; import { ScrollTrigger } from 'https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js'; import { Lenis } from 'https://unpkg.com/lenis@1.1.5/dist/lenis.min.js'; document.addEventListener("DOMContentLoaded", () => { gsap.registerPlugin(ScrollTrigger); const lenis = new Lenis(); lenis.on("scroll", ScrollTrigger.update); gsap.ticker.add((time) => { lenis.raf(time * 1000); }); gsap.ticker.lagSmoothing(0); const cardContainer = document.querySelector(".card-container"); const stickyHeader = document.querySelector(".sticky-header h1"); let isGapAnimationCompleted = false; let isFlipAnimationCompleted = false; function initAnimations() { ScrollTrigger.getAll().forEach((trigger) => trigger.kill()); const mm = gsap.matchMedia(); mm.add("(max-width: 999px)", () => { document .querySelectorAll(".card, .card-container, .sticky-header h1") .forEach((el) => (el.style = "")); return {}; }); mm.add("(min-width: 1000px)", () => { ScrollTrigger.create({ trigger: ".sticky", start: "top top", end: `+=${window.innerHeight * 4}px`, scrub: 1, pin: true, pinSpacing: true, onUpdate: (self) => { const progress = self.progress; if (progress >= 0.1 && progress 0.25) { gsap.set(stickyHeader, { y: 0, opacity: 1, }); } if (progress = 0.35 && !isGapAnimationCompleted) { gsap.to(cardContainer, { gap: "20px", duration: 0.5, ease: "power3.out", }); gsap.to(["#card-1", "#card-2", "#card-3"], { borderRadius: "20px", duration: 0.5, ease: "power3.out", }); isGapAnimationCompleted = true; } else if (progress < 0.35 && isGapAnimationCompleted) { gsap.to(cardContainer, { gap: "0px", duration: 0.5, ease: "power3.out", }); gsap.to("#card-1", { borderRadius: "20px 0 0 20px", duration: 0.5, ease: "power3.out", }); gsap.to("#card-2", { borderRadius: "0px", duration: 0.5, ease: "power3.out", }); gsap.to("#card-3", { borderRadius: "0 20px 20px 0", duration: 0.5, ease: "power3.out", }); isGapAnimationCompleted = false; } if (progress >= 0.7 && !isFlipAnimationCompleted) { gsap.to(".card", { rotationY: 180, duration: 0.75, ease: "power3.inOut", stagger: 0.1, }); gsap.to(["#card-1", "#card-3"], { y: 30, rotationZ: (i) => [-15, 15][i], duration: 0.75, ease: "power3.inOut", }); isFlipAnimationCompleted = true; } else if (progress < 0.7 && isFlipAnimationCompleted) { gsap.to(".card", { rotationY: 0, duration: 0.75, ease: "power3.inOut", stagger: -0.1, }); gsap.to(["#card-1", "#card-3"], { y: 0, rotationZ: 0, duration: 0.75, ease: "power3.inOut", }); isFlipAnimationCompleted = false; } }, }); return () => {}; }); } initAnimations(); let resizeTimer; window.addEventListener("resize", () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(() => { initAnimations(); }, 250); }); }); [/code] Это основано на учебнике CodeGrid, который я нашел на YouTube (который демонстрирует, как должен выглядеть конечный результат): [youtube]_F1t2Ux-znk[/youtube] Выглядит относительно просто, но у меня никак не работает... просто мне повезло, верно? Где у меня код идет не так? Еще раз спасибо. Подробнее здесь: [url]https://stackoverflow.com/questions/79830297/cant-get-scroll-animation-code-to-execute[/url]