To trigger GSAP animations on scroll using ScrollTrigger, load GSAP + the ScrollTrigger plugin, register it with gsap.registerPlugin(ScrollTrigger), then attach a scrollTrigger config (with trigger, start, end, and optionally scrub or pin) to any gsap.to(), gsap.from(), or timeline. ScrollTrigger converts scroll position into animation progress — no scroll-event listeners, no manual math. On WordPress, you enqueue the two scripts and drop the same JS into a Bricks Builder Code element.

Why Bricks Builder Pairs So Well With GSAP
Unlike heavier legacy page builders that wrap every element in nested div soup, Bricks Builder outputs lean, semantic HTML. That matters more than most people realize: GSAP’s ScrollTrigger plugin measures your page by calculating exact pixel positions on load. The cleaner your markup, the more predictable those calculations are.
That said, clean markup alone won’t save you from the four issues below — those come from how and when the browser renders content, not just what the HTML looks like.
Issue #1: Flash of Unstyled Content (FOUC) Before Animations Load
The Symptom
For a split second on page load, your content is fully visible in its final position. Then it snaps down to its “start” state and begins the animation you actually wanted the visitor to see.
The Fix
Many beginners set opacity: 0 directly inside the Bricks Builder UI. This is a common mistake — it can create accessibility issues for screen readers and often conflicts with GSAP’s own animation engine.
Instead, create a global utility class in Bricks (for example .gsap-reveal) and add it to your Global CSS:
/* Hide elements safely before JS takes over */
.gsap-reveal {
visibility: hidden;
}Then animate with autoAlpha instead of opacity:
gsap.to(".gsap-reveal", {
y: 0,
autoAlpha: 1, // switches visibility to 'inherit' AND fades opacity in one property
duration: 1.2,
ease: "power3.out"
});This keeps elements invisible but still occupying layout space until GSAP is ready to take over — no flash, no layout shift.
Issue #2: Incorrect ScrollTrigger Start and End Points
The Symptom
You set start: "top 80%", but the animation fires way too early or too late compared to what you expected.
The Fix
This almost always comes down to lazy-loaded images. WordPress and Bricks Builder both lazy-load images by default. When GSAP measures the page on load, an unloaded image might report a height of 0px. Once it finishes loading, the page shifts — but GSAP doesn’t automatically know that happened.
Two ways to solve it:
- Set explicit width/height or aspect ratios on every Image element in the Bricks Builder UI. This reserves the correct space in the layout before the image even downloads.
- Force a recalculation after everything has finished loading:
window.addEventListener("load", () => {
// Redraws all ScrollTrigger lines after fonts and images finish rendering
ScrollTrigger.refresh();
});Issue #3: Jumpy or Stuttering Animation on Mobile Browsers
The Symptom
The animation runs perfectly on desktop, but on an iPhone or Android browser it stutters and recalculates constantly while scrolling.
The Fix
Mobile browsers hide and show the address bar as you scroll, which continuously changes the viewport height (vh). Since ScrollTrigger reacts to viewport size changes, this can trigger unnecessary recalculations on every scroll tick.
Add this configuration once, at the very top of your script, before any ScrollTrigger instances are created:
// Prevent unnecessary recalculations from mobile address bar resizing
ScrollTrigger.config({ ignoreMobileResize: true });
// Optional: smooth out iOS overscroll bounce on pinned sections
ScrollTrigger.normalizeScroll(true);Issue #4: Pinning Creates Unwanted Whitespace
The Symptom
You use pin: true to lock a background element in place while content scrolls over it, but GSAP inserts a “pin-spacer” wrapper that pushes your layout down, breaking your Bricks structure.
The Fix
Disable automatic pin spacing and manage the layering manually:
let ctx = gsap.context(() => {
const bgLayer = document.querySelector(".fixed-transparent-bg");
const scrollSection = document.querySelector(".foreground-scroll-section");
if (bgLayer && scrollSection) {
ScrollTrigger.create({
trigger: scrollSection,
start: "top top",
end: "bottom bottom",
pin: bgLayer,
pinSpacing: false, // stops GSAP from adding extra padding
scrub: true
});
}
});
Wrapping your code in gsap.context() also makes cleanup much easier — especially important if your site uses Bricks Builder’s AJAX page transitions (see FAQ below).
Quick Reference: Common Fixes at a Glance
| Issue | Beginner Mistake | Better Approach | Why It Matters |
|---|---|---|---|
| FOUC / Flicker | opacity: 0 in Bricks UI |
visibility: hidden in CSS + autoAlpha in GSAP |
Prevents accessibility issues and layout flashes |
| Broken Triggers | Manual pixel offsets (+=500px) |
Explicit image dimensions + ScrollTrigger.refresh() |
Scales correctly across devices |
| Mobile Stutter | Turning animation off on mobile | ScrollTrigger.config({ ignoreMobileResize: true }) |
Keeps animation consistent everywhere |
| Pinning Whitespace | Negative CSS margins | pinSpacing: false |
Preserves clean Bricks Builder structure |
Real-World Examples Worth Studying
Looking at how established sites handle Web Animation can clarify best practices:
- Luxury e-commerce sites typically lock in strict aspect ratios on product grids so scroll-triggered reveals never miscalculate, regardless of connection speed.
- Apple’s product pages rely heavily on
ScrollTrigger.normalizeScroll()for their scrubbed 3D hardware showcases, smoothing out trackpad inertia so animations don’t overshoot.
FAQ
Q1: Why does my GSAP animation break after Bricks Builder’s AJAX page transitions? A: AJAX navigation doesn’t perform a hard page refresh, so old ScrollTrigger instances stay active in memory and conflict with the new page’s DOM. Wrap your GSAP code in gsap.context(), listen for the Bricks AJAX transition event, and call ctx.revert() to clean up old animations before the new page renders.
Q2: How do I read overlapping ScrollTrigger markers during development? A: Instead of the default markers: true, customize marker styling directly in your ScrollTrigger config, for example setting distinct colors and an indent value to visually separate overlapping trigger lines.
Q3: Why does scrub: true feel jittery on Windows machines with a standard mouse? A: Trackpads send smooth, continuous scroll data, while standard mouse wheels send “stepped” data. Changing scrub: true to a numeric value like scrub: 1 adds a short easing delay that smooths out the choppy input into a fluid glide.
Final Takeaway
Most GSAP and ScrollTrigger problems in Bricks Builder come down to timing — the browser changing the page after GSAP already did its math. Once you build the habit of reserving space for lazy-loaded content, refreshing ScrollTrigger after full load, and configuring mobile behavior up front, you’ll spend far less time debugging and far more time refining the animation itself.

