惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
InfoQ
Hugging Face - Blog
Hugging Face - Blog
月光博客
月光博客
量子位
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
SegmentFault 最新的问题
罗磊的独立博客
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
L
LINUX DO - 最新话题
T
Threatpost
Cisco Talos Blog
Cisco Talos Blog
The GitHub Blog
The GitHub Blog
V
V2EX
SecWiki News
SecWiki News
P
Privacy & Cybersecurity Law Blog
Forbes - Security
Forbes - Security
T
Troy Hunt's Blog
S
Security @ Cisco Blogs
Martin Fowler
Martin Fowler
Attack and Defense Labs
Attack and Defense Labs
A
Arctic Wolf
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Register - Security
The Register - Security
Blog — PlanetScale
Blog — PlanetScale
The Last Watchdog
The Last Watchdog
T
Tor Project blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cisco Blogs
P
Proofpoint News Feed
O
OpenAI News
Hacker News - Newest:
Hacker News - Newest: "LLM"
小众软件
小众软件
雷峰网
雷峰网
H
Heimdal Security Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
Engineering at Meta
Engineering at Meta
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
C
Cyber Attacks, Cyber Crime and Cyber Security
Webroot Blog
Webroot Blog
C
Check Point Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
T
Threat Research - Cisco Blogs
人人都是产品经理
人人都是产品经理
Hacker News: Ask HN
Hacker News: Ask HN
The Hacker News
The Hacker News
V
Vulnerabilities – Threatpost
Microsoft Security Blog
Microsoft Security Blog

Matthias Ott

Hello Again, World This, Still Not for Everyone The Shape of Friction WeissKlang L1 – Punching Above Its Weight Continvoucly Morged Value Webspace Invaders To Affinity and Beyond The Mystery of Storytelling Amateurs! Echoes of Connection Linear() Is Not (That) Linear Adding AVIF and WebP Support to My Craft CMS Site Challenge Acoustic Room Treatment and Building Sound Panels, Part 1: Planning Play On Overshoot The HTML Output Element Listening Closely Compressed Fluid Typography The Lifeblood of the Web What Could Go Wrong? That’s My Rank Making Space CSS :is() :where() the Magic Happens Visual Regression Testing for External URLs With Playwright Jane Goodall’s Famous Last Words European Tech Alternatives 🇪🇺 Independent Type Foundry Advent Calendar – Day 24: NaN Independent Type Foundry Advent Calendar – Day 23: Typotheque Independent Type Foundry Advent Calendar – Day 22: 205TF Independent Type Foundry Advent Calendar – Day 21: HvD Fonts Independent Type Foundry Advent Calendar – Day 20: Frere-Jones Type Independent Type Foundry Advent Calendar – Day 19: Fontwerk Independent Type Foundry Advent Calendar – Day 18: Vectro Independent Type Foundry Advent Calendar – Day 17: Studio René Bieder Independent Type Foundry Advent Calendar – Day 16: R-Typography Independent Type Foundry Advent Calendar – Day 15: David Jonathan Ross Independent Type Foundry Advent Calendar – Day 14: Interval Type Independent Type Foundry Advent Calendar – Day 13: Newglyph Independent Type Foundry Advent Calendar – Day 12: Swiss Typefaces Independent Type Foundry Advent Calendar – Day 11: Sharp Type Independent Type Foundry Advent Calendar – Day 10: Colophon Foundry Independent Type Foundry Advent Calendar – Day 9: Commercial Type Independent Type Foundry Advent Calendar – Day 8: Letters from Sweden Independent Type Foundry Advent Calendar – Day 7: Lineto Independent Type Foundry Advent Calendar – Day 6: Ohno Type Company Independent Type Foundry Advent Calendar – Day 5: Milieu Grotesque Independent Type Foundry Advent Calendar – Day 4: TypeMates Independent Type Foundry Advent Calendar – Day 3: Klim Type Foundry Independent Type Foundry Advent Calendar – Day 2: Dinamo Independent Type Foundry Advent Calendar – Day 1: Grilli Type The Independent Type Foundry Advent Calendar 2022 A Conversation With ChatGPT ChatGPT, please explain websites in the words of William Shakespeare Transient Frameworks Leaving Twitter Behind Converting Your Twitter Archive to Markdown The Wrong Question It Wasn’t Written Syndicating Posts from Your Personal Website to Twitter and Mastodon Suspension None of Your Business Shitty Code Prototypes Doing Our Part Patch That Package Brain Dump Generating Accessibility Test Results for a Whole Website With Evaluatory The CSS Cascade, a Deep Dive Updates About Updates How to Delete Your Commit History in Git Unblocking Your Writing Blocks, Part 2: I’m Not an Expert nor a “Thought Leader” Connections No Wrong Notes Better Options Design Debt Finite and Infinite Games Don’t Assume, Validate. Necessity Is the Ultimate Teacher One Egg Go Deep There Is No Secret Code Balancing Risk Blue Eyes, Brown Eyes The Shortcut Boomerang My RSS Feed Collection of Personal Websites Frequency The Illusion of Control The Decisions Journey Write It Down Nownownow Into the Personal-Website-Verse Considering the Opposite What is it for? Unlimited Bowling. Never done. We Are Team Internet. We Need to Save #NetNeutrality. Progressive Search Data loss (also) by JavaScript Books I Will Definitely Maybe Read in 2017 Starting to Write Notes
View Transitions: The Smooth Parts
Matthias Ott · 2025-10-23 · via Matthias Ott

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.

~