August 25, 2026
Page transitions done right
Last week I came across the website of Brand Creatives, a Dutch agency. It has a lovely page transition: click a link and a pink curtain with a curved edge rises from the bottom, shows their slogan for a moment, and lifts off again to reveal the next page. I liked it so much that I wanted it for my own website. So I looked under the hood.
How they do it
The site is built in Webflow and the transition is powered by Barba.js, GSAP (plus its CustomEase, SplitText and ScrollTrigger plugins) and Lenis for smooth scrolling. Barba turns the site into a single page application: it intercepts every click, fetches the next page with JavaScript and swaps the content container inside the current document. GSAP then animates a panel with two curved caps and a logo during Barba’s leave and enter hooks.
That is about 180 kB of JavaScript libraries before a single line of their own code runs. Their own code is another 750 lines, and here is the interesting part: less than a third of it is about the animation. The rest re-initializes Webflow interactions (Webflow = a low-code website builder), restarts Lenis, kills and refreshes ScrollTrigger, updates the navigation, fires a virtual pageview for analytics, restarts background videos and applies a color theme, all by hand, after every navigation. That is the price of a single page application: the browser no longer does these things for you, because as far as the browser is concerned, you never left the page. So you need to rewrite all this logic.
The better way
Meanwhile browsers have learned a new trick: cross-document view transitions. You opt in with one line of CSS on both pages:
@view-transition { navigation: auto; }
From then on, when you click a link, the browser takes a snapshot of the page you are leaving, loads the next page without showing it, and lets your CSS animate the two snapshots before it hands over the real page. Every click is still a real, boring page load. Nothing to fetch, nothing to swap, nothing to re-initialize.
For the splash screen I added a hidden element to every page and eight lines of JavaScript that show it for exactly as long as the transition runs:
window.addEventListener('pagereveal', function (e) {
if (!e.viewTransition) return;
document.documentElement.classList.add('vt-active');
e.viewTransition.finished.finally(function () {
document.documentElement.classList.remove('vt-active');
});
});
Because the element has a ‘view-transition-name’, the browser captures it as a separate snapshot. The splash itself never moves. An animated ‘clip-path’ reveals it from the bottom and hides it again, while the old page drifts up and the new page slides into place. The curved edge is a ‘shape()’ whose control point starts on the edge (a flat line) and bows outward as it travels. The whole thing is about 80 lines of CSS. You can see it in action and copy the code at code.usecue.com.
Why this is better
It has less weight. There is a 200kb difference between these solutions. My website tries to load as little code as possible, so I prefer the lightweight solution.
It cannot break your page. The single page application approach has a long tail of bugs: a third party embed that assumes a fresh page, an event listener registered twice, a video that does not restart, a scroll position that is off… Complexity means bugs, many bugs.
The browser keeps doing its job. Back and forward buttons, scroll restoration, deep links, analytics pageviews, focus management, screen readers announcing a new page: all native. Barba has to emulate every one of them. That complexity has a cost in terms of weight and speed.
Accessibility comes for free. One media query with ‘@view-transition { navigation: none; }’ and users who prefer reduced motion simply get a normal page load. No JavaScript branches.
The honest downsides
There are two, and I think they are small.
Firefox does not support cross-document view transitions yet. Firefox users get a plain page load, which is exactly what they got before. Chrome and Safari cover the vast majority of visitors, and Firefox will follow.
And you have less choreographic freedom. GSAP can stagger, split text and react to anything mid-flight. CSS animations on snapshots cannot be changed once they have started. In practice this limits you to transforms, opacity and clip paths, which is plenty for a curtain, a wipe, a slide or a fade. If your transition needs a physics engine, you are probably overdoing it anyway.
Conclusion
The page transition on brandcreatives.nl is beautiful, but they chose to use a client-side router, almost 200 kilobytes of libraries and hundreds of lines of code whose only job is to undo the side effects of that router. Not the best solution, as the browser now gives you the same effect with a normal website, a few lines of CSS and no side effects at all. Better for your visitors, better for your budget, better for your sanity.
Happy coding!
() Joost van der Schee