Coming from feature-rich themes like Enfold, Avada, or Divi to GeneratePress can feel like a trade-off. Yes, you get blazing fast performance and clean code, but suddenly those built-in parallax effects, animated sections, and fancy scrolling features are gone. And that’s by design – GeneratePress stays lean by not including every possible feature.
But here’s what I’ve learned after migrating dozens of client sites to GeneratePress: you don’t have to sacrifice those professional effects. You just need to be more intentional about adding them. When a client asks for parallax scrolling, animations, or interactive elements, instead of reaching for a heavy plugin that adds jQuery dependencies and 50 features you’ll never use, you can add exactly what you need with GSAP.
This tutorial shows you how to add smooth parallax effects and scroll animations using GenerateBlocks and GSAP ScrollTrigger – keeping the lightweight philosophy that made you choose GeneratePress in the first place. GSAP is the industry standard for web animations, used by Apple, Google, and Nike. While it’s larger than single-purpose libraries (70kb), it replaces multiple animation plugins with one professional-grade solution. Want to dive deeper? Check out [GSAP’s extensive learning resources](https://gsap.com/resources/).
In under 10 minutes, you’ll have parallax, fade animations, diagonal movement, and more – all the effects those page builder themes offer, but with better performance and more control.
Step 1 — Enqueue GSAP ScrollTrigger
First, let’s add GSAP to your site with conditional loading – it only loads on pages that actually use the animations. Add this code to your child theme’s functions.php or wherever you manage your scripts.
function enqueue_gsap_scrolltrigger() {
global $post;
// Only check on singular pages
if (is_singular() && isset($post->post_content)) {
// Check if page content contains gsap classes
if (strpos($post->post_content, 'gsap-') !== false) {
// Enqueue GSAP core
wp_enqueue_script('gsap', 'https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js', array(), '3.12.5', true);
// Enqueue ScrollTrigger plugin
wp_enqueue_script('gsap-scrolltrigger', 'https://cdn.jsdelivr.net/npm/[email protected]/dist/ScrollTrigger.min.js', array('gsap'), '3.12.5', true);
// Enqueue CSS
wp_enqueue_style('gsap-styles', get_stylesheet_directory_uri() . '/assets/css/gsap-scrolltrigger.css', array(), '1.0.0');
// Initialize GSAP animations (see Step 3 for full code)
wp_add_inline_script('gsap-scrolltrigger', $init_script);
}
}
}
add_action('wp_enqueue_scripts', 'enqueue_gsap_scrolltrigger');
This smart loading approach means GSAP only loads when you’ve actually added a gsap- class to a container – keeping pages without animations completely free of unnecessary scripts.
Step 2 — Add the CSS Utility Classes
Save this minified CSS as /assets/css/gsap-scrolltrigger.css in your child theme:
.gsap-parallax{will-change:transform}.gsap-fade-up,.gsap-fade-left,.gsap-fade-right,.gsap-scale{opacity:0}.gsap-horizontal{will-change:transform}.gsap-pin{position:relative}.gsap-hero{min-height:100vh;position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center}.gsap-hero-bg{position:absolute;top:0;left:0;width:100%;height:120%;object-fit:cover;z-index:-1}.gsap-section{position:relative;overflow:hidden;padding:100px 0}.gsap-float{position:absolute;pointer-events:none}.gsap-stagger>*{opacity:0}.gsap-text-reveal{overflow:hidden}.gsap-text-reveal>*{transform:translateY(100%)}.gsap-rotate{will-change:transform}.gsap-morph{will-change:transform}.gsap-timeline{position:relative}.gsap-scrub{will-change:transform}.gsap-diagonal{will-change:transform}.gsap-layer-back{z-index:-2}.gsap-layer-mid{z-index:-1}.gsap-layer-front{z-index:1}.gsap-layer-top{z-index:10}@media(max-width:768px){.gsap-mobile-disable{transform:none!important}.gsap-mobile-hide{display:none}}
Step 3 — Initialize GSAP Animations
Add this initialization script to your enqueue function (this is the $init_script variable from Step 1):
$init_script = '
gsap.registerPlugin(ScrollTrigger);
// Vertical parallax
gsap.utils.toArray(".gsap-parallax").forEach((elem) => {
const speed = elem.dataset.speed || -5;
gsap.to(elem, {
yPercent: speed * 10,
ease: "none",
scrollTrigger: {
trigger: elem,
start: "top bottom",
end: "bottom top",
scrub: true
}
});
});
// Horizontal parallax
gsap.utils.toArray(".gsap-horizontal").forEach((elem) => {
const speed = elem.dataset.hspeed || 50;
gsap.to(elem, {
xPercent: speed,
ease: "none",
scrollTrigger: {
trigger: elem,
start: "top bottom",
end: "bottom top",
scrub: true
}
});
});
// Diagonal movement (the holy grail!)
gsap.utils.toArray(".gsap-diagonal").forEach((elem) => {
const vSpeed = elem.dataset.speed || -5;
const hSpeed = elem.dataset.hspeed || 5;
const tl = gsap.timeline({
scrollTrigger: {
trigger: elem,
start: "top bottom",
end: "bottom top",
scrub: 1
}
});
tl.to(elem, {
yPercent: vSpeed * 10,
xPercent: hSpeed * 10,
ease: "none"
});
});
// Fade animations (all directions)
["up", "down", "left", "right"].forEach(direction => {
gsap.utils.toArray(`.gsap-fade-${direction}`).forEach((elem) => {
const config = {
opacity: 0,
duration: elem.dataset.duration || 1,
delay: elem.dataset.delay || 0,
scrollTrigger: {
trigger: elem,
start: elem.dataset.start || "top 85%",
toggleActions: "play none none reverse"
}
};
switch(direction) {
case "up": config.y = elem.dataset.distance || 60; break;
case "down": config.y = -(elem.dataset.distance || 60); break;
case "left": config.x = -(elem.dataset.distance || 60); break;
case "right": config.x = elem.dataset.distance || 60; break;
}
gsap.from(elem, config);
});
});
// Scale animation
gsap.utils.toArray(".gsap-scale").forEach((elem) => {
gsap.from(elem, {
scale: elem.dataset.scale || 0.8,
opacity: 0,
duration: elem.dataset.duration || 1,
scrollTrigger: {
trigger: elem,
start: elem.dataset.start || "top 80%"
}
});
});
// Stagger animations for child elements
gsap.utils.toArray(".gsap-stagger").forEach((elem) => {
const children = elem.children;
gsap.from(children, {
y: elem.dataset.distance || 30,
opacity: 0,
duration: elem.dataset.duration || 0.6,
stagger: elem.dataset.stagger || 0.1,
delay: elem.dataset.delay || 0,
scrollTrigger: {
trigger: elem,
start: elem.dataset.start || "top 80%"
}
});
});
// Pin sections
gsap.utils.toArray(".gsap-pin").forEach((elem) => {
ScrollTrigger.create({
trigger: elem,
start: elem.dataset.pinstart || "top top",
end: elem.dataset.pinend || "bottom top",
pin: true,
pinSpacing: elem.dataset.pinspacing !== "false"
});
});
// Counter animation
gsap.utils.toArray(".gsap-counter").forEach((elem) => {
const target = elem.dataset.target || 100;
const duration = elem.dataset.duration || 2;
const obj = { value: 0 };
gsap.to(obj, {
value: target,
duration: duration,
ease: "power1.inOut",
scrollTrigger: {
trigger: elem,
start: "top 80%",
once: true
},
onUpdate: () => {
elem.textContent = Math.round(obj.value);
}
});
});
';
Step 4 — Add Animations to Any Container
Adding animations is simple. On any GenerateBlocks container:
- Add a
gsap-class to the Additional CSS Classes field - Add data attributes for customization
That’s it. Your container now has professional animations.
GenerateBlocks Settings Examples:
For Parallax:
- Additional CSS Classes:
gsap-parallax - Custom Attributes:
- Name:
data-speed - Value:
-7(negative = slower, positive = faster)
- Name:
For Diagonal Movement:
- Additional CSS Classes:
gsap-diagonal - Custom Attributes:
data-speed|-5(vertical speed)data-hspeed|10(horizontal speed)
For Fade Animation:
- Additional CSS Classes:
gsap-fade-up - Custom Attributes (optional):
data-distance|80(distance to travel)data-duration|1.5(animation duration)data-delay|0.3(delay before start)
Step 5 — Common Animation Patterns
Hero Section with Parallax Background
In GenerateBlocks:
- Create a Container with your hero content
- Add a background image via GB settings
- Add class:
gsap-parallax gsap-hero - Add attribute:
data-speed|-7
Staggered Cards Animation
Perfect for feature boxes or team grids:
- Create a GB Grid container
- Add class:
gsap-stagger - Add attributes:
data-stagger|0.2data-distance|50 - All child containers will animate in sequence
Diagonal Floating Elements
For decorative elements that move diagonally:
<!-- In GB Custom HTML Attributes -->
class="gsap-diagonal"
data-speed="-10"
data-hspeed="20"
Fade In Content Sections
<!-- Fade from bottom -->
class="gsap-fade-up"
data-distance="100"
data-duration="1.2"
<!-- Fade from left -->
class="gsap-fade-left"
data-distance="80"
data-delay="0.3"
Pinned Section (Sticky Scrolling)
class="gsap-pin"
data-pinstart="top top"
data-pinend="+=500"
Animated Counters
<!-- For a number counter -->
class="gsap-counter"
data-target="1234"
data-duration="2.5"
Step 6 — Performance Optimization
Mobile Control
GSAP animations can be heavy on mobile. Add gsap-mobile-disable to any element to disable its animation on mobile devices (under 768px).
Reduce Animations
Don’t go overboard. 5-10 animated elements per page is plenty. More than that risks janky scrolling.
Use GPU Acceleration
The CSS file already includes will-change: transform for smooth animations, but avoid animating properties like width or height – stick to transform and opacity.
Available Animation Classes Reference
Parallax Effects
gsap-parallax– Vertical parallax (data-speed)gsap-horizontal– Horizontal parallax (data-hspeed)gsap-diagonal– Diagonal movement (data-speed, data-hspeed)
Fade Animations
gsap-fade– Simple fadegsap-fade-up– Fade in from bottomgsap-fade-down– Fade in from topgsap-fade-left– Fade in from leftgsap-fade-right– Fade in from right
Transform Effects
gsap-scale– Scale in effectgsap-rotate– Rotation on scroll (data-rotate)gsap-flip– 3D flip animation
Advanced Effects
gsap-stagger– Animate children in sequencegsap-pin– Pin element while scrollinggsap-counter– Animated number countergsap-text-reveal– Reveal text line by line
Data Attributes
All animations support these optional data attributes:
data-speed– Vertical movement speed (-10 to 10)data-hspeed– Horizontal movement speeddata-distance– Distance for fade animationsdata-duration– Animation duration in secondsdata-delay– Delay before animation startsdata-start– ScrollTrigger start positiondata-scale– Scale factordata-stagger– Stagger timing for children
Troubleshooting
Animations not working? Check if the class starts with gsap- and the page was refreshed after adding it.
Diagonal movement not working? Make sure you’re using both data-speed and data-hspeed attributes with the gsap-diagonal class.
Performance issues? Add gsap-mobile-disable class or reduce the number of animated elements.
Elements jumping on load? The CSS file includes opacity settings to prevent this. Make sure it’s properly loaded.
Bonus: Quick Implementation in Query Loops
This setup works perfectly with GenerateBlocks Query Loops. Just add the animation classes to your Loop Item Block: