GSAP podstawy
GSAP (GreenSock Animation Platform) to najpopularniejsza biblioteka do animacji w internecie. Korzysta z niej ponad 11 milionów stron, w tym wiele nagradzanych projektów. GSAP pozwala animować praktycznie wszystko, co JavaScript może dotknąć - elementy HTML, SVG, Three.js, komponenty Reacta, a nawet dowolne obiekty JavaScript. Dlaczego GSAP, a nie CSS animations czy Web Animations API?
- Wydajność - GSAP optymalizuje renderowanie, omijając layout thrashing
- Pełna kontrola nad czasem - play, pause, reverse, seek, timeScale
- Cross-browser - działa tak samo w każdej przeglądarce
- Timeline - zaawansowane sekwencjonowanie animacji
- Pluginy - ScrollTrigger, Draggable, MorphSVG, MotionPath i wiele innych
Instalacja
Najprościej jest załączyć bibliotekę z CDN.<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>Użycie npm:
npm install gsapNastępnie importujemy:
import gsap from 'gsap';
// lub konkretny plugin:
import { ScrollTrigger } from 'gsap/ScrollTrigger';
Jeśli chcemy dołączyć pluginy:
// Po załadowaniu biblioteki zarejestruj pluginy: gsap.registerPlugin(ScrollTrigger);
Podstawy - Tween
Tween to pojedyncza animacja. W GSAP mamy cztery typy: gsap.to() - Animuje od obecnej wartości do podanej gsap.from() - Animuje od podanej wartości do obecnej gsap.fromTo() - Definiujesz start i koniec gsap.set() - Natychmiast ustawia właściwości (bez animacji)gsap.to() - najpopularniejsza metoda
gsap.to('.box', {
x: 200, // translateX: 200px
duration: 2, // czas trwania w sekundach
ease: 'power2.out'
});
gsap.from() - animacja "od"
gsap.from('.box', {
x: -200,
opacity: 0,
duration: 1.5,
ease: 'back.out(1.7)' // efekt "overshoot"
});
gsap.fromTo() - pełna kontrola
gsap.fromTo('.box',
{ x: 0, opacity: 0, scale: 0.5 }, // stan początkowy
{ x: 300, opacity: 1, scale: 1, duration: 2 } // stan końcowy
);
Transformacje - co można animować?
GSAP animuje praktycznie wszystko. Oto najczęściej używane właściwości:Translacje i obrót
gsap.to('.element', {
x: 100, // translateX(100px)
y: 50, // translateY(50px)
rotation: 45, // rotate(45deg)
scale: 1.5, // scale(1.5)
scaleX: 2, // scaleX(2)
scaleY: 0.5, // scaleY(0.5)
skewX: 10, // skewX(10deg)
skewY: 5, // skewY(5deg)
transformOrigin: 'center top'
});
Właściwości CSS
gsap.to('.box', {
backgroundColor: '#3498db',
borderRadius: '20px',
boxShadow: '0 10px 30px rgba(0,0,0,0.3)',
padding: '40px',
filter: 'blur(4px)',
duration: 1
});
SVG
gsap.to('#myPath', {
attr: {
d: 'M10 50 Q100 10 190 50', // morphing ścieżki
fill: '#e74c3c',
stroke: '#c0392b',
strokeWidth: 4
},
duration: 2
});
Dowolny obiekt JavaScript
const obj = { value: 0, color: '#ff0000' };
gsap.to(obj, {
value: 100,
duration: 2,
ease: 'power4.inOut',
onUpdate: () => {
console.log(`Wartość: ${obj.value}`);
document.getElementById('counter').textContent = Math.round(obj.value);
}
});
Timeline - sekwencjonowanie animacji
Timeline to kontener na tweeny, który pozwala precyzyjnie umieszczać animacje w czasie.Podstawowe sekwencjonowanie
const tl = gsap.timeline();
tl.to('.box1', { x: 200, duration: 1 })
.to('.box2', { y: 100, duration: 1 })
.to('.box3', { rotation: 360, duration: 2 });
Animacje odtwarzają się jedna po drugiej.
Parametr position - precyzyjne pozycjonowanie
const tl = gsap.timeline();
// Absolutny czas (sekundy od początku)
tl.to('.box1', { x: 200, duration: 1 }, 0);
// Relatywny czas (+=2 = 2 sekundy po poprzedniej animacji)
tl.to('.box2', { y: 100, duration: 1 }, '+=2');
// Nаłоżenie (-=0.5 = 0.5 sekundy przed końcem poprzedniej)
tl.to('.box3', { opacity: 1, duration: 1 }, '-=0.5');
// W tym samym momencie co box1
tl.to('.box4', { scale: 1.5, duration: 1 }, 0);
Etykiety (Labels) - czytelne sekwencjonowanie
const tl = gsap.timeline();
tl.to('.box1', { x: 200, duration: 1 })
.add('scene2', '+=1') // dodaje etykietę 1s po poprzedniej
.to('.box2', { y: 100, duration: 1 }, 'scene2')
.to('.box3', { rotation: 360, duration: 2 }, 'scene2+=0.5')
.add('scene3', '+=2');
// Nawigacja po etykietach
tl.play('scene2');
tl.seek('scene3');
Kontrola Timeline
const tl = gsap.timeline();
tl.to('.box', { x: 300, duration: 2 });
// Pauzowanie
tl.pause();
// Odtwarzanie
tl.play();
// Przewijanie do konkretnej sekundy
tl.seek(1);
// Zmiana prędkości (0.5 = połowa, 2 = podwójna)
tl.timeScale(0.5);
// Odwracanie
tl.reverse();
// Ustawienie postępu (0 = początek, 1 = koniec)
tl.progress(0.5);
// Restart
tl.restart();
Właściwości specjalne
- duration - Czas trwania (sekundy) duration: 2
- delay - Opóźnienie startu (sekundy) delay: 1
- repeat - Liczba powtórzeń ('-1' = nieskończenie) repeat: 3
- yoyo - Odwraca animację co powtórzenie yoyo: true
- stagger - Opóźnienie między elementami stagger: 0.1
- ease - Krzywa wygładzania ease: 'power2.out'
- onComplete - Callback po zakończeniu onComplete: myFunc
- onUpdate - Callback na każdy tick onUpdate: update
Powtórzenia i yoyo
gsap.to('.box', {
x: 200,
duration: 1,
repeat: -1, // nieskończone powtórzenie
yoyo: true, // odwraca kierunek co cycle
ease: 'power1.inOut'
});
Stagger - animacja grup elementów
// Każdy element z .dot animuje się z 0.1s opóźnienia
gsap.to('.dot', {
y: -50,
duration: 0.8,
stagger: 0.1,
ease: 'back.out(2)'
});
Easing - krzywe wygładzania
// Wbudowane easingi
gsap.to('.box', { x: 200, ease: 'power2.out' });
gsap.to('.box', { x: 200, ease: 'elastic.out(1, 0.5)' });
gsap.to('.box', { x: 200, ease: 'bounce.out' });
gsap.to('.box', { x: 200, ease: 'expo.inOut' });
gsap.to('.box', { x: 200, ease: 'circ.inOut' });
gsap.to('.box', { x: 200, ease: 'sine.inOut' });
// Easing z konfiguracją
gsap.to('.box', {
x: 200,
ease: 'power4.inOut',
duration: 2
});
ScrollTrigger - animacje wyzwalane scrollowaniem
ScrollTrigger to najpopularniejszy plugin GSAP. Poniżej przykład jego podstawowego użycia.
gsap.registerPlugin(ScrollTrigger);
gsap.to('.box', {
x: 300,
scrollTrigger: {
trigger: '.section',
start: 'top center', // kiedy górna krawędź sekcji dotyka środka viewporta
end: 'bottom center', // kiedy dolna krawędź sekcji dotyka środka viewporta
scrub: true, // animacja powiązana ze scrollowaniem
toggleActions: 'play pause resume reverse'
}
});
Przyklejanie elementu
gsap.to('.hero', {
y: 0,
scrollTrigger: {
trigger: '.hero',
start: 'top top',
end: '+=500',
scrub: true,
pin: true, // "przykleja" element podczas scrollowania
anticipatePin: 1
}
});
Animacja SVG podczas scrollowania
// Oblicz długość ścieżki SVG
const path = document.querySelector('#draw-path');
const length = path.getTotalLength();
// Ukryj ścieżkę
gsap.set(path, {
strokeDasharray: length,
strokeDashoffset: length
});
// Animuj "rysowanie" podczas scrollowania
gsap.to(path, {
strokeDashoffset: 0,
ease: 'none',
scrollTrigger: {
trigger: '.section',
start: 'top center',
end: 'bottom center',
scrub: true
}
});
Parallax effect
// Tło porusza się wolniej niż treść
gsap.to('.parallax-bg', {
y: -200,
ease: 'none',
scrollTrigger: {
trigger: '.parallax-section',
start: 'top bottom',
end: 'bottom top',
scrub: true
}
});
Sekwencja w ScrollTrigger
const tl = gsap.timeline({
scrollTrigger: {
trigger: '.reveal-section',
start: 'top 80%',
end: 'top 20%',
scrub: 1, // 1s opóźnienia dla płynności
pin: true
}
});
tl.from('.reveal-section .title', {
opacity: 0,
y: 60,
duration: 1
})
.from('.reveal-section .text', {
opacity: 0,
y: 40,
duration: 1
}, '-=0.5')
.from('.reveal-section .image', {
scale: 0.8,
opacity: 0,
duration: 1
}, '-=0.5');
Multiple ScrollTriggers z markerami (debug)
gsap.utils.toArray('.section').forEach((section, i) => {
gsap.from(section.querySelector('.content'), {
scrollTrigger: {
trigger: section,
start: 'top center+=100',
end: 'bottom center',
scrub: true,
// markers: true, // odkomentuj w celu debugowania
onEnter: () => section.classList.add('active'),
onLeave: () => section.classList.remove('active'),
onEnterBack: () => section.classList.add('active'),
onLeaveBack: () => section.classList.remove('active')
},
x: 0,
opacity: 1,
duration: 1,
ease: 'power2.out'
});
});
ScrollSmoother - płynne scrollowanie
ScrollSmoother dodaje "inercję" scrollowaniu, nadając animacji bardziej płynne odczucie.
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
const smoother = ScrollSmoother.create({
wrapper: '#smooth-wrapper',
content: '#smooth-content',
smooth: 1.5, // czas wygładzania (im więcej, tym płynniej)
smoothTouch: 0.1, // mniejsze wygładzanie na dotyku
normalizeScroll: true,
ignoreMobileResize: true
});
// Zaktualizuj ScrollTrigger po zmianie layoutu
ScrollTrigger.addEventListener('refresh', () => smoother.scrollTop(s smoother.scrollTop()));
ScrollTrigger.refresh();
Animacja SVG - animacja ścieżek
Przykład morphingu ścieżki SVG:
gsap.to('#shape', {
attr: {
d: 'M10 10 H90 V90 H10 L10 10 Z' // nowa ścieżka
},
duration: 2,
ease: 'power2.inOut'
});
Animacja SVG z CSS:
gsap.to('#mySVG', {
x: 100,
y: 50,
rotation: 45,
scale: 1.2,
duration: 1.5,
ease: 'back.out(1.7)'
});
Animacja kolorów
gsap.to('.box', {
backgroundColor: '#3498db',
color: '#ffffff',
borderColor: '#2980b9',
duration: 1.5,
ease: 'power2.inOut'
});
Animacja wartości niestandardowych (bez DOM)
const stats = { value: 0, angle: 0 };
const tl = gsap.timeline({
onUpdate: () => {
console.log(`Wartość: ${stats.value.toFixed(1)}, Kąt: ${stats.angle.toFixed(1)}°`);
},
onComplete: () => {
console.log('Animacja zakończona!');
}
});
tl.to(stats, { value: 100, duration: 2, ease: 'power4.out' })
.to(stats, { angle: 360, duration: 1, ease: 'power2.inOut' }, '-=1');
Poniżej pełny kod przykładu animacji landing page.
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GSAP Landing Page</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', sans-serif; background: #0a0a0a; color: white; }
.section { min-height: 100vh; display: flex; align-items: center; justify-content: center; flex-direction: column; }
.hero { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.hero h1 { font-size: 4rem; opacity: 0; transform: translateY(50px); }
.hero p { font-size: 1.5rem; opacity: 0; margin-top: 1rem; }
.content { background: #0a0a0a; }
.cards { display: flex; gap: 2rem; margin-top: 3rem; }
.card { background: #1a1a2e; padding: 2rem; border-radius: 12px; width: 250px; opacity: 0; transform: translateY(60px); }
.card h3 { color: #667eea; margin-bottom: 0.5rem; }
.scroll-section { min-height: 200vh; background: #0f0f23; position: relative; }
.pin-box { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 3rem; color: #667eea; }
</style>
</head>
<body>
<div class="section hero">
<h1>Witaj w GSAP</h1>
<p>Potężne animacje dla nowoczesnego webu</p>
</div>
<div class="section content">
<h2>Możliwości GSAP</h2>
<div class="cards">
<div class="card"><h3>Transformacje</h3><p>x, y, rotation, scale i wiele więcej</p></div>
<div class="card"><h3>ScrollTrigger</h3><p>Animacje wyzwalane scrollowaniem</p></div>
<div class="card"><h3>Timeline</h3><p>Precyzyjne sekwencjonowanie</p></div>
</div>
</div>
<div class="scroll-section">
<div class="pin-box">Scrolluj!</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
<script>
gsap.registerPlugin(ScrollTrigger);
// Hero entrance
gsap.to('.hero h1', {
opacity: 1,
y: 0,
duration: 1,
delay: 0.3,
ease: 'power3.out'
});
gsap.to('.hero p', {
opacity: 1,
y: 0,
duration: 1,
delay: 0.6,
ease: 'power3.out'
});
// Cards stagger
gsap.to('.card', {
opacity: 1,
y: 0,
duration: 0.8,
stagger: 0.2,
scrollTrigger: {
trigger: '.cards',
start: 'top 80%',
toggleActions: 'play none none reverse'
},
ease: 'back.out(1.7)'
});
// Pinning section
gsap.to('.pin-box', {
scale: 2,
rotation: 360,
scrollTrigger: {
trigger: '.scroll-section',
start: 'top top',
end: 'bottom bottom',
scrub: true,
pin: true
}
});
</script>
</body>
</html>
Wskazówki i best practices
1. Używaj transformacji zamiast layout properties
// Dobrze - wydajne
gsap.to('.box', { x: 200, y: 100, rotation: 45 });
// Źle - powoduje re-layout
gsap.to('.box', { left: 200, top: 100 });
2. Zawsze cleanup w React
x
useEffect(() => {
const ctx = gsap.context(() => {
// animacje
});
return () => ctx.revert(); // ← zawsze!
}, []);
3. scrub z opóźnieniem dla płynności
scrollTrigger: {
scrub: 1, // 1s opóźnienia - bardziej eleganckie
// scrub: true // true = natychmiastowe (bardziej responsywne)
}
4. Debugowanie z markerami
scrollTrigger: {
trigger: '.section',
start: 'top center',
end: 'bottom center',
scrub: true,
markers: true // pokazuje strefy start/end - odkomentuj przy debugu
}
5. Stagger z gridem
gsap.to('.grid-item', {
opacity: 1,
y: 0,
stagger: {
each: 0.05,
grid: 'auto',
from: 'center' // animacja rozchodzi się od środka
},
scrollTrigger: {
trigger: '.grid',
start: 'top 80%'
}
});
GSAP to złoty standard animacji w JavaScript. Jego moc leży w:
- Prostym API - gsap.to() wystarcza na start
- Timeline - zaawansowane sekwencjonowanie
- ScrollTrigger - animacje wyzwalane scrollowaniem w 5 liniach kodu
- Wydajności - GSAP omija problemy z renderowaniem w przeglądarce
- Uniwersalności - HTML, SVG, Canvas, React, Vue, Three.js - działa wszędzie