View Tran­si­tions: The Smooth Parts

Now that cross-document view transitions are gradually making their way into modern browsers, now seems like the perfect time to explore them, if you haven’t already. They are, in fact, surprisingly straightforward to implement. And just like we’ve seen with modern images, view transitions can be slapped onto existing projects as a progressive enhancement.

That my website is now called a “multi-page app” (MPA) is still a hilarious thought 😂, but hey – I’ll take it if I get a smoother experience with basically just one line of CSS:

@view-transition {
   navigation: auto;
}

You add this @view-transition declaration to all pages of your site that should be transitioned – in my case I added it to the main.css – and every browser that supports cross-document view-transitions, will now fade between the (same-origin) pages. And: You can try it on this website already. 🥳 To see view transitions in action, click on “Home” or ”Articles” in the main navigation, for example. But please come back here after that!

How It Works #

The way cross-document view transitions work is that when you navigate to a new page, the browser starts loading it in the background and captures a snapshot. It then cross-fades from your current page snapshot (the old state) to the new one.

But with one important detail: the page loading process remains incremental. The browser waits for the <head> to load before starting the transition animation, but then decides independently how much of the <body> to wait for. This can affect the actual user experience. First-time visitors or users on slower connections may not see transitions at all if the animation start before content has been loaded. Or, elements could still be loading while the animation is already running, leading to a weird and clunky experience. Repeat visitors with cached resources are more likely to see smooth transitions. But in practice, the experience can vary between navigations on the same device, depending on the connection speed, for example. Thanks to Martin Trapp for highlighting this. Martin runs a fantastic project, by the way – a bag of tricks, explainers, and demos around view transitions. Be sure to check that out.

Waiting for Content to Load #

What we can do to make the experience a bit smoother is to tell the browser which content to wait for before the animations can be started. For this, we use the new expect value for the rel attribute of the <link> tag and specify the element the browser should wait for by its ID. This could be your #main content, the #body, or any other important element – you decide.


  
    ...
    
  
  
    ...
  
  

Also keep in mind that if #body or #main loads slowly – because of heavy images or a network fetch, for example – the transition may feel delayed or janky. So always test and consciously decide if this is a good solution in your specific case. Maybe this is also a good reason to improve the overall performance of your site?

Respecting prefers-reduced-motion #

Something that can make the whole experience more accessible is to respect the prefers-reduced-motion media query, so that people with motion sensitivity will not see the animation:

@view-transition {
   navigation: auto;
}

@media (prefers-reduced-motion) {
  @view-transition {
    navigation: none;
  }
}

But: you should always consider whether this is actually necessary – which depends on the type of animation. It’s certain kinds of motion, or degrees of motion that can cause problems, not simply the presence of any animation. Simple fades between pages, for example, are generally seen as quite safe and less likely to trigger vestibular disorders. If you are using grow, scroll, or slide animations, however, better use prefers-reduced-motion to reduce or remove those motion-heavy transitions.

A Few View Transition CSS Tricks #

Now, once you start looking under the hood, things can become a bit more complicated. This post won’t go into all the details – we don’t have time for that – but I’ll highlight a few of the things that are really straightforward to implement and can further improve the experience with a few quick moves.

Fine-tuning Animations #

If you want to adjust the animation used for the transition, you will have to dig a bit deeper and use one (or more) of the many pseudo-elements, that are available once you activate view transitions for a page. As I mentioned, view transitions work by taking snapshots of the old and new states – of the root document and all named transition that have a view-transition-name. With those snapshots, the API then constructs an actual pseudo-element tree:

::view-transition
└─ ::view-transition-group(root)
   └─ ::view-transition-image-pair(root)
      ├─ ::view-transition-old(root)
      └─ ::view-transition-new(root)

The ::view-transition sits in an overlay over everything else on the page. The ::view-transition-group contains the image pair being used for the transition.

The cool thing is: all the animations are now done using CSS animations. So you can use regular CSS to adjust the duration or the timing function, for instance:

::view-transition-group(root) {
	animation-duration: 600ms;
	animation-timing-function: cubic-bezier(0.3, 0, 0.8, 1);
}

Or, you can even define @keyframe animations and set the animations for the old and new state to completely individual animations.

::view-transition-old(root) {
	animation-name: dash-out;
}
::view-transition-new(root) {
	animation-name: dash-in;
}

@keyframes dash-out {
	to {
		translate: 100% 0;
		opacity: 1;
	}
}

@keyframes dash-in {
	from {
		translate: -100% 0;
		opacity: 1;
	}
}

This is still a very basic example. But the ability to use standard CSS keyframe animations gives you plenty of flexibility to craft unique, tailored transitions for your specific use case.

There’s also a lot more you can do to fine-tune animations, for example by using the JavaScript features of the View Transitions API and the pagereveal and pageswap events. Or defining your own transition types and then using different types to animate forwards and backwards between states. That’s a topic for another post, though. For now, I'll probably stick with a more basic implementation on this site.

Progressive enhancement FTW!

And in case you want to learn a bit more, watch Bramus and Kevin explaining view transitions in more detail: https://www.youtube.com/watch?v=quvE1uu1f_I

This is post 20 of Blogtober 2025.

~

28 Webmentions

  1. It might be helpful to link to the conversation Kevin had with Bramus when you mention it under a few other CSS tricks. I found that you linked to it at the end of the article but I had to look for it. Just a suggestion. Thanks for your thoughts on this subject. Very helpful.

6 Reposts

ⓘ Webmentions are a way to notify other websites when you link to them, and to receive notifications when others link to you. Learn more about Webmentions.