Section 1
Section 2
It is highly commendable to avoid external libraries when possible. It keeps your site lightweight, reduces technical debt, and prevents you from loading 100kb of JavaScript for a 5kb animation.
You hit the nail on the head regarding the mechanics: to achieve this, the sections must be overlapping. The cleanest, most elegant way to pull this off without any external libraries relies on standard document flow and a single, incredibly powerful CSS property: position: sticky.
Here are two methods to achieve this in Bricks, depending on the exact visual nuance you want.
Method 1: The Pure CSS “Slide-Over” Wipe (Recommended)
This is the holy grail for this specific effect. It requires zero JavaScript, respects Bricks’ standard vertical stacking in the editor, and perfectly handles sections that are taller than the screen.
How it works: By applying position: sticky; bottom: 0; to your sections, you tell the browser: “Let this section scroll normally. But when the bottom of this section hits the bottom of the viewport, pin it there.” Because the section is pinned, as the user keeps scrolling, the next section (which is naturally lower in the DOM and therefore has a higher stacking order) will slide up from the bottom, sliding over the pinned section. Visually, this looks identical to a bottom-to-top wipe.
The Code:
-
In Bricks, build your sections stacked vertically as normal.
-
Give every section in your river journey a shared class, for example,
river-section. -
Add this custom CSS to the class or in your global stylesheet:
.river-section {
position: sticky;
bottom: 0;
/* Optional: Ensure sections are at least the height of the screen */
min-height: 100vh;
/* Optional: Add a slight shadow to the top of the section to emphasize the "wipe" edge as it moves up */
box-shadow: 0px -10px 30px rgba(0,0,0,0.1);
}
Crucial Bricks Consideration: For position: sticky to work, none of the parent containers (all the way up to the <body>) can have overflow: hidden applied to them. If the sticky effect isn’t working, check your Bricks wrapper containers for overflow settings.
Method 2: The Vanilla JS “Clip-Path Mask” (The True Cut-Away)
If you specifically want the upper section to dissolve/cut away to reveal the lower section underneath it (rather than the lower section sliding over the upper one), Method 1 won’t work. You have to reverse the stacking order and use JavaScript to animate a CSS clip-path mask.
How it works: We have to create “spacer” divs. When a section hits the bottom, we pin it to the screen. We then measure how far the user continues to scroll down the “spacer” and translate that scroll distance into a percentage, shrinking the clip-path of the upper section to reveal the one below.
The Setup in Bricks:
-
Assign the class
river-mask-sectionto your sections. -
Ensure you manually set
z-indexin Bricks so the first section is highest (e.g., Section 1:z-index: 10, Section 2:z-index: 9).
The CSS:
.river-mask-section {
position: relative;
/* We will use JS to toggle this to 'fixed' or 'sticky' */
clip-path: inset(0 0 0% 0); /* The last zero is the bottom mask */
will-change: clip-path; /* Performance optimization */
}
The Vanilla JS: Note: This is a simplified boilerplate. In a production environment, you would want to throttle the scroll event using requestAnimationFrame for performance.
document.addEventListener('DOMContentLoaded', () => {
const sections = document.querySelectorAll('.river-mask-section');
window.addEventListener('scroll', () => {
let scrollY = window.scrollY;
sections.forEach((section, index) => {
// Don't mask the very last section
if (index === sections.length - 1) return;
const rect = section.getBoundingClientRect();
const sectionBottom = rect.bottom + scrollY;
const windowBottom = scrollY + window.innerHeight;
// If we have scrolled past the bottom of this section
if (windowBottom > sectionBottom) {
// Pin the section (conceptually) and calculate how much to mask
let overScroll = windowBottom - sectionBottom;
// Convert that overscroll into a percentage based on viewport height
let maskPercentage = (overScroll / window.innerHeight) * 100;
// Cap it at 100%
if (maskPercentage > 100) maskPercentage = 100;
section.style.clipPath = `inset(0 0 ${maskPercentage}% 0)`;
} else {
// Reset if scrolled back up
section.style.clipPath = `inset(0 0 0% 0)`;
}
});
});
});
(Keep in mind: If you use the JS method, the browser doesn’t naturally know how much scroll space to provide once a section is clipped away. You usually have to inject empty height: 100vh spacer divs underneath your sections via JS to maintain the scrollbar length.)
Given that Method 1 requires just three lines of CSS and zero JavaScript, it is vastly superior for keeping your site clean while achieving the exact visual behavior you described.
How do you envision this wipe effect translating to mobile devices, where scroll-snapping and screen pinning can sometimes feel restrictive on smaller touch screens?
Section 3
It is highly commendable to avoid external libraries when possible. It keeps your site lightweight, reduces technical debt, and prevents you from loading 100kb of JavaScript for a 5kb animation.
You hit the nail on the head regarding the mechanics: to achieve this, the sections must be overlapping. The cleanest, most elegant way to pull this off without any external libraries relies on standard document flow and a single, incredibly powerful CSS property: position: sticky.
Here are two methods to achieve this in Bricks, depending on the exact visual nuance you want.
Method 1: The Pure CSS “Slide-Over” Wipe (Recommended)
This is the holy grail for this specific effect. It requires zero JavaScript, respects Bricks’ standard vertical stacking in the editor, and perfectly handles sections that are taller than the screen.
How it works: By applying position: sticky; bottom: 0; to your sections, you tell the browser: “Let this section scroll normally. But when the bottom of this section hits the bottom of the viewport, pin it there.” Because the section is pinned, as the user keeps scrolling, the next section (which is naturally lower in the DOM and therefore has a higher stacking order) will slide up from the bottom, sliding over the pinned section. Visually, this looks identical to a bottom-to-top wipe.
The Code:
-
In Bricks, build your sections stacked vertically as normal.
-
Give every section in your river journey a shared class, for example,
river-section. -
Add this custom CSS to the class or in your global stylesheet:
.river-section {
position: sticky;
bottom: 0;
/* Optional: Ensure sections are at least the height of the screen */
min-height: 100vh;
/* Optional: Add a slight shadow to the top of the section to emphasize the "wipe" edge as it moves up */
box-shadow: 0px -10px 30px rgba(0,0,0,0.1);
}
Crucial Bricks Consideration: For position: sticky to work, none of the parent containers (all the way up to the <body>) can have overflow: hidden applied to them. If the sticky effect isn’t working, check your Bricks wrapper containers for overflow settings.
Method 2: The Vanilla JS “Clip-Path Mask” (The True Cut-Away)
If you specifically want the upper section to dissolve/cut away to reveal the lower section underneath it (rather than the lower section sliding over the upper one), Method 1 won’t work. You have to reverse the stacking order and use JavaScript to animate a CSS clip-path mask.
How it works: We have to create “spacer” divs. When a section hits the bottom, we pin it to the screen. We then measure how far the user continues to scroll down the “spacer” and translate that scroll distance into a percentage, shrinking the clip-path of the upper section to reveal the one below.
The Setup in Bricks:
-
Assign the class
river-mask-sectionto your sections. -
Ensure you manually set
z-indexin Bricks so the first section is highest (e.g., Section 1:z-index: 10, Section 2:z-index: 9).
The CSS:
.river-mask-section {
position: relative;
/* We will use JS to toggle this to 'fixed' or 'sticky' */
clip-path: inset(0 0 0% 0); /* The last zero is the bottom mask */
will-change: clip-path; /* Performance optimization */
}
The Vanilla JS: Note: This is a simplified boilerplate. In a production environment, you would want to throttle the scroll event using requestAnimationFrame for performance.
document.addEventListener('DOMContentLoaded', () => {
const sections = document.querySelectorAll('.river-mask-section');
window.addEventListener('scroll', () => {
let scrollY = window.scrollY;
sections.forEach((section, index) => {
// Don't mask the very last section
if (index === sections.length - 1) return;
const rect = section.getBoundingClientRect();
const sectionBottom = rect.bottom + scrollY;
const windowBottom = scrollY + window.innerHeight;
// If we have scrolled past the bottom of this section
if (windowBottom > sectionBottom) {
// Pin the section (conceptually) and calculate how much to mask
let overScroll = windowBottom - sectionBottom;
// Convert that overscroll into a percentage based on viewport height
let maskPercentage = (overScroll / window.innerHeight) * 100;
// Cap it at 100%
if (maskPercentage > 100) maskPercentage = 100;
section.style.clipPath = `inset(0 0 ${maskPercentage}% 0)`;
} else {
// Reset if scrolled back up
section.style.clipPath = `inset(0 0 0% 0)`;
}
});
});
});
(Keep in mind: If you use the JS method, the browser doesn’t naturally know how much scroll space to provide once a section is clipped away. You usually have to inject empty height: 100vh spacer divs underneath your sections via JS to maintain the scrollbar length.)
Given that Method 1 requires just three lines of CSS and zero JavaScript, it is vastly superior for keeping your site clean while achieving the exact visual behavior you described.
How do you envision this wipe effect translating to mobile devices, where scroll-snapping and screen pinning can sometimes feel restrictive on smaller touch screens?
