Create Silky Smooth Header Animations on Scroll! - Motion.page/GSAP - ScrollTrigger

In this video, we will show you how to add awesome curves to your sections as you scroll down.

In this tutorial, Luke demonstrates how to create a scroll-triggered header animation where the navigation bar shrinks in width and changes background and text color dynamically. This subtle but powerful effect enhances user experience and is fully responsive, thanks to Motion Page’s scroll trigger and the use of CSS variables within Core Framework.


Steps

Setting Up the Header in Bricks Builder:

Create a New Header Template:

A new template is created in Bricks and designated as a “Header” type. Within the template, Luke adds a section containing a three-column layout for a left logo/icon, center navigation links, and a right-side call-to-action button.

Apply BEM Classes and Styling:

Using the Core Framework BEM class generator, each element is given consistent class names. Padding, spacing, alignment, and color variables (--dark, --light) are applied for clarity and maintainability.

Fix the Header Position:

The entire header is given a position: fixed so it remains visible on scroll. A container wrapper ensures the header stays centered even when its width is reduced during the animation.


Creating the Scroll Animation in Motion Page:

Build a Scroll-Triggered Timeline:

A new timeline is created and set to use the Scroll trigger, locked to the scroll bar with a 0.3s duration. The navigation bar is targeted using the scanner, and z-index is increased to ensure it’s scannable above overlapping content.

Animate the Header Width:

The width is reduced from its default to 800px as the user scrolls down. The animation begins when the top of the header hits the top of the viewport and ends 300px later (top → min -300px), creating a smooth, proportional shrink effect.

Change Background Color with Scroll:

Luke sets the header’s background to var(--bg-body) initially and animates it to var(--dark) on scroll. To prevent hue blending issues during the color transition, he updates all variables in Core Framework from HEX to HSLA and removes any saturation — ensuring a clean, linear animation.


Updating Navigation Link and Icon Colors:

Link Color Transition:

A new animation node is added targeting the BEM class for the nav links. The text color is changed from var(--dark) to var(--light) on scroll.

Icon Color Transition:

Similarly, another node targets the icon and updates its color to var(--light), ensuring full visual consistency in the header as the scroll-triggered transformation occurs.


Result

The result is a lightweight yet dynamic scroll effect for headers: a shrinking navigation bar with responsive color transitions. The design adapts perfectly to both light and dark themes thanks to the use of Core Framework variables. This keeps the effect not only modern and clean, but also theme-aware and easy to manage.


Conclusion

Luke’s scroll-responsive header tutorial is a perfect example of how to use Motion Page’s scroll triggers alongside Bricks Builder and Core Framework. With no JavaScript required and full responsiveness out of the box, designers can implement elegant UI interactions that elevate the overall website experience.

By leveraging variables, BEM structure, and motion design principles, this effect is both visually polished and easy to maintain. Whether you’re creating a blog, portfolio, or product site, this header technique adds polish and professionalism with minimal effort.

Video transcript

Hello guys, welcome back to the channel. My name is Luke, and in today’s video I’d like to show you how to create this simple effect. This was a user request.

As I scroll down the page, you’ll see the header shrinks in width and changes color. This is in a fixed position — nothing too special — but it gives a very nice, unique effect.

In Bricks Builder, if I change this to light mode and save, then refresh, you can see that it works out of the box. I’m using variables, so we get the same effect in opposite colors.

Let’s get started.

The first thing I’m going to do is add a new template for our header. In Bricks templates, let’s add a new template. I’ll call this “Header” and make sure the template type is set to “Header.” Let’s edit it with Bricks.

The first thing we need is a section. Inside the section, I’m going to add a block — this will be my main nav. I’ll also change this to light mode to make my life easier. I’ll rename this “Navbar.”

In here, I want three blocks — left, center, and right. On the left, we want our logo. In the center, our links. And on the right, a CTA button or something like that.

I’ll just label these for now. Let’s use an icon on the left to keep it simple. In the center, I’ll add one link for now. And on the right, I’ll add a button element. I’ll give it a “button” class and make the text small.

Now I’m going to add some classes to these elements so we can style everything accordingly.

I’ll use the BEM generator — this will be available in Core Framework in a future update. Right now, it’s just a prototype, but I’m using it to add BEM classes to all these elements.

For the navbar, I want it to be row layout and center everything. For the icon, I’ll make it a bit smaller. The center area also needs to be a row with centered content. The right section should push everything to the right.

Back in the parent container, I want everything centered. I’ll add a column gap — medium — and duplicate the link a couple more times.

For the main navbar block, I’ll add some padding — just a little top and bottom — and for the sides, let’s do medium. Then I’ll give it a border radius — set it to “full” to round everything. I think it could use a little more padding on top, so I’ll tweak that. Let’s try XS top and bottom. Yeah, that looks better.

For the text links, I’ll set the color using a variable — var(--dark). I’ll also give the icon the same dark color.

Next, I’ll go to the section itself and give it a class — let’s call it “nav-section.” I’ll reduce the padding on the section — it’s too tall. Let’s try 2XS top and bottom.

Now we need to make this header fixed. That way, when I scroll, it stays visible. Just to show you, I’ll add a new section underneath and give it a height of 200vh. Now when I scroll, you can see the header is fixed in place. Perfect.

Let’s delete that test section.

One last thing I want to do is make sure the navbar is always centered when we scroll down — even when the width gets smaller. So I’ll go to the container, give it a class — “nav-section__container” — and make sure the content stays centered.

Save that.

Now let’s create a page so we can fill it with some dummy content. I’ll call it “Header Example Page,” publish, and edit with Bricks.

To make things easier, I’m just going to import a few Violet templates. Make sure “Import images” is checked, and I’ll insert a couple of examples — maybe three. That should give us some scrollable content.

I’ll assign my custom code, and because the header is fixed, I’ll add extra padding to the first section to prevent it from overlapping.

I’ve noticed a few spacing issues. I just updated Core Framework, so I’ll view this on the frontend. Let’s go to WordPress > Core Framework and save it again.

That fixed it. Sometimes after updating Core, you just need to resave.

Now, as you can see, we’ve got some dummy content, and the header is fixed — exactly what we want.

Now we’re ready to edit this navigation in Motion Page.

I’ll create a new timeline and call it “Custom Header.” Let’s open the example page to preview the effect.

Since this is triggered on scroll, I’ll select the “Scroll” trigger and lock it to the scroll bar. My personal preference is a duration of 0.3 seconds.

We want to target the nav itself. But you’ll notice I can’t scan the element — that’s because the content below is overlapping it. Let’s go back to Bricks > Templates > Header > Edit with Bricks.

I’ll change the z-index of the header. I could target the class directly, but I want to show why it’s not working. Let’s set z-index: 10, save, and refresh Motion Page.

Now I can scan and target the navbar.

As we scroll, we want to change the width. The original state is fine. In the “To” tab, I’ll go to Dimensions and change the width to 800px. You’ll see it shrink here.

I don’t want it to trigger immediately, so I’ll adjust the scroll start and end points. Let’s say the animation starts when the top of the nav hits the top of the viewport — that’s 0px. So I’ll set the Start to “top” and “0px.”

Now the green line appears at the top.

Then I’ll set the End trigger to “top” at “min -300px” — that means when the nav scrolls up past the top by 300 pixels, the animation finishes.

Now you can see it transitions more smoothly with the scroll — exactly what we want.

Next, I want to change the background color of the navbar. In Core Framework, I’m using variables. Right now the background is empty — it’s transparent.

Let’s go back to Bricks and explicitly set the background color to var(--bg-body) — same as the page background. You won’t see a difference visually, but it helps later.

Back in Motion Page, refresh.

Now, I’ll animate the background color to change to var(--dark) as we scroll.

You’ll notice a strange color transition — like yellow to green to purple — before it lands on the dark. I’ll show you why in a second.

Next, we need to change the text color of the navigation links. Right now they’re dark, but we want them light on scroll.

Add another animation node and target the link class. In the “To” tab, set the text color to var(--light).

Now the text lightens as we scroll.

We’ll do the same with the icon. Add another animation node, target the icon’s BEM class, and change the text color to var(--light).

Now let’s fix the strange background color transition.

Open Core Framework and inspect your color variables.

I’ll convert all relevant colors — bg-body, light, dark — to use hsla instead of hex. That allows for smoother transitions.

Look at var(--dark) — you’ll see it has a bit of saturation and a slight hue, which causes that weird color blending.

To fix it, remove all saturation. I’ll go into --dark, --light, and --bg-body, and ensure their saturation is set to 0%. Save changes.

Back in Motion Page, refresh.

Now the background color animates in a smooth, linear way — no more weird transitions.

I’ve already saved the timeline. Let’s check it on the frontend.

This is the page. As I scroll down, we get this nice transition with a fixed header. Looks pretty good.

The nice thing is — because I’m using variables — if I change to a dark theme and refresh the page, the effect still works out of the box. As I scroll, everything updates accordingly.

So there you have it — a simple tutorial, but an effective header animation.

I hope you like it. If you do, please don’t forget to give us a thumbs up, and we’ll be back very soon with another video.

Thank you.

100 %