AI & ML

7 Essential View Transitions Techniques to Enhance Your Web Apps

· 5 min read

View transitions are genuinely impressive, and they're becoming increasingly common across the web. You've probably encountered several that made you think "wow" and immediately want to implement them in your own work.

That said, view transitions can be challenging to grasp initially. Simple implementations exist, but anything beyond a basic cross-fade requires coordinating multiple components.

The most effective way to learn is by examining working code, experimenting with it, and building from there. That's why I've assembled seven view transition recipes with complete setup instructions and live demos.

Feel free to jump straight to the recipes and copy what you need. However, if you want a solid foundation in view transitions, I recommend reading this quick introduction first.

One important note: while view transitions have achieved Baseline status and work across all major browsers at the time of writing, specific animation types may have varying support levels. Always test your implementations across target browsers.

The setup

Each view transition requires some initial configuration. Start by opting in using the @view-transition at-rule on both pages involved in the transition. If you're working with templates, add this to your header template for site-wide coverage.

@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
types: <transition-type>;
}
}

The <transition-type> is a placeholder for the types descriptor, which we've explored in depth previously. In essence, types names your specific transition so you can manage multiple transitions without conflicts. Check that linked article for comprehensive details.

Notice the @view-transition sits within a prefers-reduced-motion: no-preference media query. This respects users who've disabled motion at the OS level.

Next, apply your animation:

html:active-view-transition-type(<transition-type>)::view-transition-old(root) {
animation: a-cool-outgoing-animation 1.4s ease forwards;
}
html:active-view-transition-type(<transition-type>)::view-transition-new(root) {
animation: a-cool-incoming-animation 1.4s ease forwards;
}

The :active-view-transition-type() pseudo-class matches the transition type defined in your @view-transition rule. For an animation named bounce, you'd write:

@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
types: bounce;
}
}

And target it with:

/* The "current" page */
html:active-view-transition-type(bounce)::view-transition-old(root) {
animation: bounce-out 1.4s ease forwards;
}
/* The page we're transitioning to */
html:active-view-transition-type(bounce)::view-transition-new(root) {
animation: bounce-in 1.4s ease forwards;
}

That covers the fundamentals. Let's dive into the recipes.

Pixelate dissolve

This effect resembles a cross-fade but adds blur as the old content fades out and new content fades in.

Full snippet
@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
types: pixelate-dissolve;
}
}
html:active-view-transition-type(pixelate-dissolve)::view-transition-old(root) {
animation: pixelate-out 1.4s ease forwards;
}
html:active-view-transition-type(pixelate-dissolve)::view-transition-new(root) {
animation: pixelate-in 1.4s ease forwards;
}
@keyframes pixelate-out {
0% {
filter: blur(0px);
opacity: 1;
}
100% {
filter: blur(40px);
opacity: 0;
}
}
@keyframes pixelate-in {
0% {
filter: blur(40px);
opacity: 0;
}
100% {
filter: blur(0px);
opacity: 1;
}
}

Wipe up

This uses clip-path to create a wipe effect where new content slides up from the bottom, replacing the old content.

The mechanism is straightforward: the outgoing page transitions from its default inset() value of 0 0 0 0 (creating a rectangle at the top, right, bottom, and left edges) by changing the bottom value to 100%, moving from top to bottom.

The incoming page starts with the top clipped at 100% and animates down to 0.

Full snippet
@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
types: wipe-up;
}
}
html:active-view-transition-type(wipe-up)::view-transition-old(root) {
animation: wipe-out 1.4s ease forwards;
}
html:active-view-transition-type(wipe-up)::view-transition-new(root) {
animation: wipe-in 1.4s ease forwards;
}
@keyframes wipe-out {
from {
clip-path: inset(0 0 0 0);
}
to {
clip-path: inset(0 0 100% 0);
}
}
@keyframes wipe-in {
from {
clip-path: inset(100% 0 0 0);
}
to {
clip-path: inset(0 0 0 0);
}
}

You can easily adapt this for wipe right, wipe down, or wipe left by adjusting the inset values. Here's a wipe right variation:

@keyframes wipe-out {
from {
clip-path: inset(0 0 0 0);
}
to {
clip-path: inset(0 0 0 100%);
}
}
@keyframes wipe-in {
from {
clip-path: inset(0 100% 0 0);
}
to {
clip-path: inset(0 0 0 0);
}
}

The wipe right follows similar logic, with the outgoing page clipping from center toward the right (second value from 0 to 100%), while the incoming page animates from 100% on the left to 0.

And here's wipe down:

@keyframes wipe-out {
from {
clip-path: inset(0 0 0 0);
}
to {
clip-path: inset(100% 0 0 0);
}
}
@keyframes wipe-in {
from {
clip-path: inset(0 0 100% 0);
}
to {
clip-path: inset(0 0 0 0);
}
}

The pattern should be clear by now.

Rotate in-out

This one's admittedly unusual and not particularly practical, but it demonstrates the creative possibilities of view transitions.

We combine scale() and rotate() functions to zoom and spin the content. The old page scales down to 0 while rotating clockwise 180deg. The new page then scales up to 1 while rotating counter-clockwise -180deg. Some opacity changes enhance the transition between states.

Full snippet
@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
types: zoom-rotate;
}
}
html:active-view-transition-type(zoom-rotate)::view-transition-old(root) {
animation: zoom-rotate-out 1.4s ease forwards;
transform-origin: center;
}
html:active-view-transition-type(zoom-rotate)::view-transition-new(root) {
animation: zoom-rotate-in 1.4s ease forwards;
transform-origin: center;
}
@keyframes zoom-rotate-out {
to {
transform: scale(0) rotate(180deg);
opacity: 0;
}
}
@keyframes zoom-rotate-in {
from {
transform: scale(0) rotate(-180deg);
opacity: 0;
}
}

Circle wipe-out

The effect here is more understated than previous examples. The subtlety stems from the shared background color between the outgoing and incoming pages, creating a smoother visual flow. With more contrasting content, the transition would be far more pronounced.

The circular reveal relies on the clip-path property with the circle() function. The animation originates from the center point, expanding from 0% (invisible) to 150% (oversized), ensuring complete coverage of the viewport.

Full snippet
@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
types: circular-wipe;
}
}
html:active-view-transition-type(circular-wipe)::view-transition-old(root) {
animation: circle-wipe-out 1.4s ease forwards;
}
html:active-view-transition-type(circular-wipe)::view-transition-new(root) {
animation: circle-wipe-in 1.4s ease forwards;
}
@keyframes circle-wipe-out {
to {
clip-path: circle(0% at 50% 50%);
}
}
@keyframes circle-wipe-in {
from {
clip-path: circle(0% at 50% 50%);
}
to {
clip-path: circle(150% at 50% 50%);
}
}

Diagonal push

This technique displaces the current page diagonally while the new page slides in from the opposite corner. The direction is configurable—this example moves from bottom-right to top-left.

The outgoing page translates to -100% on both X and Y axes, pushing it off-screen. The incoming page enters from the opposite corner, transitioning from translate(100%, 100%) to its default 0% position. Strategic opacity adjustments enhance the visual polish.

Full snippet
@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
types: diagonal-push;
}
}
html:active-view-transition-type(diagonal-push)::view-transition-old(root) {
animation: diagonal-out 1.4s ease forwards;
}
html:active-view-transition-type(diagonal-push)::view-transition-new(root) {
animation: diagonal-in 1.4s ease forwards;
}
@keyframes diagonal-out {
to {
transform: translate(-100%, -100%);
opacity: 0;
}
}
@keyframes diagonal-in {
from {
transform: translate(100%, 100%);
opacity: 0;
}
}

Curtain reveal

This transition mimics theatrical curtains closing on the departing page and parting to reveal the new one. The inset() function defines rectangular clipping regions positioned at 50% from both left and right edges. As the old page exits, these regions expand to 50%, then contract to 0 as the new page enters, creating a center-outward reveal effect.

Full snippet
@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
types: curtain;
}
}
html:active-view-transition-type(curtain)::view-transition-old(root) {
animation: curtain-out 1.4s ease forwards;
}
html:active-view-transition-type(curtain)::view-transition-new(root) {
animation: curtain-in 1.4s ease forwards;
}
@keyframes curtain-out {
from {
clip-path: inset(0 0 0 0);
}
}
@keyframes curtain-in {
from {
clip-path: inset(0 50% 0 50%);
}
to {
clip-path: inset(0 0 0 0);
}
}

3D flip

This effect simulates a double-sided card rotating along the Z-axis, with the outgoing page flipping away as the incoming page flips into view.

Full snippet
@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
types: flip-3d;
}
}
html:active-view-transition-type(flip-3d)::view-transition-old(root) {
animation: flip-out 1.4s ease forwards;
}
html:active-view-transition-type(flip-3d)::view-transition-new(root) {
animation: flip-in 1.4s ease forwards;
}
@keyframes flip-out {
0% {
transform: rotateY(0deg) translateX(0vw);
}
100% {
transform: rotateY(-90deg) translateX(-100vw);
opacity: 1;
}
}
@keyframes flip-in {
0% {
transform: rotateY(90deg) translateX(100vw);
}
100% {
transform: rotateY(0deg) translateX(0vw);
}
}

Any cool recipes you want to share?

Got your own view transition techniques? Share them! Bramus has assembled an excellent interactive collection of view transition examples that's worth exploring for additional inspiration.


7 View Transitions Recipes to Try originally handwritten and published with love on CSS-Tricks. You should really get the newsletter as well.