A Prismatic Page Transition in Nuxt

A short-ish writeup on how I made the transitions for this website as well as what shortcomings the chosen transition effect has..

I am pretty fond of how the transitions on this website turned out (even though they don't work in all browsers), So I thought I would share how they are made and done.

The basics

First of all I have made this website using Nuxt. In Nuxt each layout or page can have a transition attached (utilizing the native Vue transition component behind the scenes) - but if a page doesn't have a specific transition name attached to it in the page component's transition property, it will default to use a transition of the name "page". Unless you do something with this information, this fact won't be used for anything, and pages simply won't transition. But you can leverage this fact to make the basics of the transitions, simply by adding a bit of css:

.page-enter-active,
.page-leave-active {
    transition: opacity 1s;
}
.page-enter,
.page-leave-to {
    opacity: 0;
}

This CSS should af course be used on the site, in my case I added a reference to it's CSS file in the nuxt.config.js file:

export default {
    ...,
    css: ['~/assets/css/transitions.css'],
    ...,
};

At this point the pages will simply fade in and out when transitioning. This will both be part of the full transition, but will also be the fallback transition in browsers that does not support the CSS backdrop-filter property (Firefox and Edge on mobile to name a few).

Adding a bit of flair

Now that's all fine and good, but let's dial it up a notch, shall we? In browsers that support it, this website will transition by blurring the content out of existence whilst animating a colorful gradient on top of it, giving a kind of prismatic look to it all.

Part of this effect comes from the fact, that I am using a light background gradient on the website. Here's the CSS for it:

html {
    ...
    background: #fff;
    background-color: #fff;
    background: -webkit-linear-gradient(top right, #E3F8FF, #FFEFE0);
    background: -moz-linear-gradient(top right, #E3F8FF, #FFEFE0);
    background: linear-gradient(to bottom left, #E3F8FF, #FFEFE0);
    background-size: cover;
    background-repeat:no-repeat;
    background-attachment: fixed;
    ...
}

Without this gradient, much of the transition effect won't happen, as this gradient is what's amplified to make for the rainbow-y effect. Next I went to my layout component and inserted a div with the class l-default__transition-overlay right after the Nuxt component that renders the page (ignore the Tailwind classes, it is that one div that matters):

<template>
    <div class="l-default w-full h-full flex">
        <div
            class="
                w-full
                max-w-1600
                m-auto
                px-24
                md:px-42
                lg:px-68
                py-68
                flex flex-col
            "
        >
            <Nuxt
                class="l-default__page flex-shrink-0"
                style="padding-bottom: clamp(0px, 100vh - 700px, 100px)"
            />
            <div class="l-default__transition-overlay flex-shrink-0"></div>
        </div>
        <SidebarArea />
    </div>
</template>

This element are used in concert with the page transition to apply the prismatic transition effect as an overlay above the rest of the website. This is done through styling, which I add after the basic transition styling in the transitions.css file from earlier:

.l-default__transition-overlay {
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    opacity: 0;
    transition: opacity 1s ease-in-out, backdrop-filter 1s;
    will-change: opacity, backdrop-filter;
    z-index: 1000;
}
.page-enter + .l-default__transition-overlay,
.page-leave-to + .l-default__transition-overlay {
    backdrop-filter: saturate(700%) hue-rotate(-300deg) blur(30px) ;
    pointer-events: auto;
    opacity: 1;
}

Important things to notice here is that the div is styled as a fixed overlay covering the whole page (don't forget pointer-events: none to make it click-through!), and that on page transition we fade in a set of background filters that A) amplify the saturation by 700%, B) rotate the hue by -300 degrees and C) blurs the website by 30px. The values used are of course completely arbitrary.

Additionally to having these filters transitioned individually, I also fade in the whole div to add a bit more smoothness to the effect.

Now, it's important that the saturation happens before the blur, as the saturation itself leaves some jagged edges around the color plamages. The saturation and the blur is what gives the colorfulness to the effect. The hue rotation gives some motion to the effect due to the diagonal background transition used on the website - by shifting the hue, the transition seems to move across the screen, and then back. A similar effect could probably be had by having the gradient background be set on the transition overlay div instead.

Anyhow, that's how the transition on this site was made. It's a shame that backdrop-filter isn't supported by all modern browsers, as that's the major drawback of this effect. If you don't care about blurring the page content, the effect could probably be replicated pretty well by moving the gradient to the overlay and instead use the better supported filter property.. But I digress - I like how the effect combines different layers of the website, rather than just being a simple fade of content or an overlay.

Hope you enjoyed,
~ Simon


Published