{"id":113,"date":"2026-03-05T02:22:26","date_gmt":"2026-03-05T02:22:26","guid":{"rendered":"https:\/\/luca05.co.uk\/article\/?p=113"},"modified":"2026-03-25T15:58:30","modified_gmt":"2026-03-25T15:58:30","slug":"view-transitions","status":"publish","type":"post","link":"https:\/\/luca05.co.uk\/article\/view-transitions\/","title":{"rendered":"View Transitions: The Future of Web Animation is Here"},"content":{"rendered":"\n<p><strong><mark style=\"background-color:rgba(0, 0, 0, 0);color:#13189a\" class=\"has-inline-color\">How a new browser feature is making smooth animations accessible to everyone<\/mark><\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>If you&#8217;ve ever visited a modern website and noticed how smoothly photos expand when you click on them, or how elegantly content slides into view, you&#8217;ve experienced the magic of web animations. Until recently, creating these polished effects required complicated code and specialist knowledge. But that&#8217;s all changing with the View Transition API.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What Are View Transitions?<\/h2>\n\n\n\n<p>Imagine you&#8217;re browsing a photo gallery on a website. You see a grid of small thumbnails and click on one. Instead of the page suddenly jumping to show a larger version, the photo smoothly grows from its small size to fill the screen. That smooth, fluid movement is a view transition.<\/p>\n\n\n\n<p>In technical terms, the View Transition API provides a mechanism for easily creating animated transitions between different website views. But really, it&#8217;s about making websites feel more natural and polished\u2014like watching a film rather than flipping through still photographs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How It Actually Works<\/h2>\n\n\n\n<p>The browser does the heavy lifting through a four-step process:<\/p>\n\n\n\n<p><strong>Step 1: Capture<\/strong><br>When someone triggers an action\u2014clicking a button, navigating, or filtering a list\u2014the browser takes a snapshot of the current view. Think of it as taking a photograph of the webpage, recording where every element sits on the page.<\/p>\n\n\n\n<p><strong>Step 2: Update the DOM<\/strong><br>Your JavaScript code runs and updates the webpage. Content changes, elements are added or removed, and the layout shifts. All of this happens in a single atomic update.<\/p>\n\n\n\n<p><strong>Step 3: Snapshot Again<\/strong><br>The browser captures the new view state. Now it has two snapshots: before and after. It can calculate exactly how much things have moved, grown, or shrunk.<\/p>\n\n\n\n<p><strong>Step 4: Animate<\/strong><br>Here&#8217;s where the magic happens. The browser creates smooth CSS animations that morph between the old and new states. Elements appear to move, scale, and fade\u2014all at 60 frames per second using your computer&#8217;s graphics processor. Then it tidies up the temporary elements it created.<\/p>\n\n\n\n<p>The brilliant part? All of this happens automatically. You don&#8217;t have to write complex animation code.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Two Types for Different Needs<\/h2>\n\n\n\n<p>View Transitions come in two flavours, depending on how your website is built:<\/p>\n\n\n\n<p><strong><mark style=\"background-color:rgba(0, 0, 0, 0);color:#13189a\" class=\"has-inline-color\">Same-Document Transitions (SPAs)<\/mark><\/strong><br>These work within a single page using the <code>document.startViewTransition()<\/code> function. They&#8217;re perfect for filtering lists, switching tabs, expanding sections, or any content changes that happen without loading a new page.<\/p>\n\n\n\n<p><a href=\"https:\/\/mdn.github.io\/dom-examples\/view-transitions\/spa\">https:\/\/mdn.github.io\/dom-examples\/view-transitions\/spa<\/a><\/p>\n\n\n\n<p><strong><mark style=\"background-color:rgba(0, 0, 0, 0);color:#13189a\" class=\"has-inline-color\">Cross-Document Transitions (MPAs)<\/mark><\/strong><br>These work automatically when you navigate between different pages. Both pages just need to opt in with a simple CSS rule, and the browser handles everything else.<\/p>\n\n\n\n<p><a href=\"https:\/\/mdn.github.io\/dom-examples\/view-transitions\/mpa\">https:\/\/mdn.github.io\/dom-examples\/view-transitions\/mpa<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Code Comparison That Says It All<\/h2>\n\n\n\n<p>Before View Transitions, creating smooth animations looked like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code>async function updateList(filter) {\n  \/\/ Animate out old content\n  await animateOut();\n  \n  \/\/ Update DOM\n  filteredItems = items.filter(item =&gt; item.type === filter);\n  renderList(filteredItems);\n  \n  \/\/ Animate in new content\n  await animateIn();\n  \n  \/\/ Handle focus, accessibility, event listeners...\n}<\/code>\n<\/code><\/pre>\n\n\n\n<p>Dozens of lines of complex code, managing states, coordinating timing, handling edge cases.<\/p>\n\n\n\n<p>With View Transitions, it&#8217;s this simple:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function updateList(filter) {\n  document.startViewTransition(() =&gt; {\n    filteredItems = items.filter(item =&gt; item.type === filter);\n    renderList(filteredItems);\n  });\n}\n<\/code><\/pre>\n\n\n\n<p>Three lines. That&#8217;s the entire difference. The browser handles all the animation logic.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why This Matters<\/h2>\n\n\n\n<p><strong>1. Less Code to Write<\/strong><br>You&#8217;re writing 3 lines instead of 50. This isn&#8217;t just about saving time\u2014it&#8217;s about being able to focus on your website&#8217;s actual functionality instead of wrestling with animation complexity.<\/p>\n\n\n\n<p><strong>2. Websites Feel Better<\/strong><br>Before View Transitions, many websites had no animations because it was too complicated. Now anyone can add smooth animations. This means regular websites\u2014not just those built by large companies\u2014will feel polished and professional.<\/p>\n\n\n\n<p><strong>3. Works Everywhere<\/strong><br>Previously, React websites used one animation tool, Vue websites used another, and vanilla JavaScript did something different. Now everyone can use View Transitions. It&#8217;s one standard tool that works across the entire web ecosystem.<\/p>\n\n\n\n<p><strong>4. Web Apps Feel Like Phone Apps<\/strong><br>This might be the most exciting change. Web applications have traditionally felt different from native phone apps\u2014less smooth and less polished. With View Transitions, web apps can be just as fluid as native applications. Users won&#8217;t feel the difference any more.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Can You Use Them Now?<\/h2>\n\n\n\n<p>The short answer: yes, but with some caveats.<\/p>\n\n\n\n<p>Over 90% of modern browsers support View Transitions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Chrome: 65%+ support<\/li>\n\n\n\n<li>Firefox: 25%+ support (recently added)<\/li>\n\n\n\n<li>Safari: 10%+ support (iOS 18+)<\/li>\n\n\n\n<li>Edge: Included in Chrome statistics<\/li>\n\n\n\n<li>Samsung Browser: 60%+ support<\/li>\n<\/ul>\n\n\n\n<p>However, the reality is nuanced. At present, support is primarily concentrated in Chrome version 111 and beyond. Whilst the technology is available, not everyone has upgraded to these newer browser versions yet.<\/p>\n\n\n\n<p>The good news? View Transitions are a progressive enhancement. If someone uses an older browser, your website still works perfectly\u2014they just won&#8217;t see the smooth animations. The functionality remains intact.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Limitations: They&#8217;re Not For Everything<\/h2>\n\n\n\n<p>View Transitions are powerful for specific use cases, but they&#8217;re not a universal solution.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What They&#8217;re Great For<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Filtering or sorting a list<\/strong> \u2014 Update results and smoothly transition to the new layout<\/li>\n\n\n\n<li><strong>Tab switching<\/strong> \u2014 Move between sections of a page with animation<\/li>\n\n\n\n<li><strong>Expanding sections<\/strong> \u2014 Accordion-style content reveals<\/li>\n\n\n\n<li><strong>Gallery navigation<\/strong> \u2014 Photo galleries, carousels<\/li>\n\n\n\n<li><strong>Dashboard view changes<\/strong> \u2014 Switching between different data visualizations<\/li>\n\n\n\n<li><strong>Page-to-page navigation<\/strong> \u2014 Links to different pages with smooth transitions<\/li>\n<\/ul>\n\n\n\n<p>If you&#8217;re changing what&#8217;s displayed on the page and want a smooth visual journey, View Transitions shine.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What They&#8217;re Not For<\/h3>\n\n\n\n<p><strong>Real-time or streaming data<\/strong>: View Transitions need a clear &#8220;before&#8221; and &#8220;after&#8221; state. If your data is constantly updating or streaming in, this API doesn&#8217;t fit.<\/p>\n\n\n\n<p><strong>Complex 3D animations<\/strong>: If you need serious 3D effects, WebGL is the tool. View Transitions are about 2D spatial transitions.<\/p>\n\n\n\n<p><strong>Huge DOM changes<\/strong>: If you&#8217;re replacing 80% of the page at once, you might see performance issues. View Transitions work best when there&#8217;s a reasonable amount of change.<\/p>\n\n\n\n<p><strong>Cases where you don&#8217;t control the update<\/strong>: Like if data comes from an external source and you don&#8217;t have control over how it changes, transitions might not make sense.<\/p>\n\n\n\n<p>The limitation is really about scope. View Transitions are for discrete state changes. They&#8217;re not for continuous animation or streaming. If you have a clear before-and-after state, and you control when the transition happens, you&#8217;re in good shape.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Best Practices: Using View Transitions Wisely<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Always Check If It Exists<\/h3>\n\n\n\n<p>javascript<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if (document.startViewTransition) {\n  document.startViewTransition(() =&gt; {\n    updateContent();\n  });\n} else {\n  updateContent();\n}<\/code><\/pre>\n\n\n\n<p>Don&#8217;t assume the API is available. Older browsers and some less common browsers won&#8217;t have it. Check first, always.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Make Sure Your Fallback Works<\/h3>\n\n\n\n<p>Test your site without View Transitions. Disable the API in DevTools if you have to. Make sure the functionality still works perfectly in browsers that don&#8217;t support it. The transition is a bonus, not a requirement.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Don&#8217;t Do Heavy Work Inside the Transition<\/h3>\n\n\n\n<p>The callback to <code>startViewTransition()<\/code> is synchronous. Don&#8217;t do expensive calculations or DOM manipulation inside it. Fetch your data first, then call the transition with the update.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. Respect When People Don&#8217;t Want Motion<\/h3>\n\n\n\n<p>Some users have accessibility needs around motion. Respect the <code>prefers-reduced-motion<\/code> media query:<\/p>\n\n\n\n<p>javascript<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const prefersReducedMotion = window.matchMedia(\n  '(prefers-reduced-motion: reduce)'\n).matches;\n\nif (prefersReducedMotion) {\n  updateContent(); \/\/ Just update, no transition\n} else if (document.startViewTransition) {\n  document.startViewTransition(() =&gt; updateContent());\n}<\/code><\/pre>\n\n\n\n<p>This is both accessible and respectful.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5. Name Your Transitions Meaningfully<\/h3>\n\n\n\n<p>If you&#8217;re giving elements transition names:<\/p>\n\n\n\n<p>css<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.hero { view-transition-name: hero-section; }\n.sidebar { view-transition-name: sidebar; }<\/code><\/pre>\n\n\n\n<p>Use names that describe what&#8217;s being transitioned, not how. <code>hero-section<\/code> is better than <code>slide-left-section<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6. Test in Multiple Browsers<\/h3>\n\n\n\n<p>Seriously test this. Use Chrome, Firefox, Safari if you can. Make sure unsupported browsers don&#8217;t break. Make sure the fallback experience is solid.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7. Document Why You&#8217;re Using Transitions<\/h3>\n\n\n\n<p>If you&#8217;re using View Transitions, add a comment explaining why. Future you will appreciate it:<\/p>\n\n\n\n<p>javascript<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Use view transition to smoothly show the selected product\n\/\/ This creates visual continuity as the user selects from the grid\nfunction selectProduct(productId) {\n  if (document.startViewTransition) {\n    document.startViewTransition(() =&gt; {\n      displayProduct(productId);\n    });\n  } else {\n    displayProduct(productId);\n  }\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-accent-3-color\">Getting Started: A Working Example<\/mark><\/h2>\n\n\n\n<p>Here&#8217;s a practical example you can actually use. It&#8217;s a photo gallery with View Transitions:<\/p>\n\n\n\n<p>html<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\"&gt;\n&lt;head&gt;\n  &lt;meta charset=\"UTF-8\"&gt;\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"&gt;\n  &lt;title&gt;Photo Gallery with View Transitions&lt;\/title&gt;\n  &lt;style&gt;\n    * { margin: 0; padding: 0; box-sizing: border-box; }\n    body { font-family: system-ui; padding: 20px; }\n    \n    .gallery-grid {\n      display: grid;\n      grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n      gap: 15px;\n      margin-bottom: 40px;\n    }\n    \n    .gallery-item {\n      cursor: pointer;\n      border-radius: 8px;\n      overflow: hidden;\n    }\n    \n    .gallery-item img {\n      width: 100%;\n      height: 150px;\n      object-fit: cover;\n    }\n    \n    .gallery-item img:hover {\n      opacity: 0.8;\n    }\n    \n    .photo-display {\n      max-width: 600px;\n    }\n    \n    .photo-display img {\n      view-transition-name: selected-photo;\n      width: 100%;\n      height: auto;\n      border-radius: 12px;\n    }\n    \n    ::view-transition-old(selected-photo) {\n      animation: shrink-out 0.3s ease-out;\n    }\n    \n    ::view-transition-new(selected-photo) {\n      animation: grow-in 0.3s ease-in;\n    }\n    \n    @keyframes shrink-out {\n      from { transform: scale(1); opacity: 1; }\n      to { transform: scale(0.8); opacity: 0; }\n    }\n    \n    @keyframes grow-in {\n      from { transform: scale(0.8); opacity: 0; }\n      to { transform: scale(1); opacity: 1; }\n    }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div class=\"gallery-grid\" id=\"gallery\"&gt;&lt;\/div&gt;\n  &lt;div class=\"photo-display\" id=\"photoDisplay\"&gt;&lt;\/div&gt;\n  \n  &lt;script&gt;\n    const photos = &#91;\n      { id: 1, src: 'photo1.jpg', title: 'Photo 1' },\n      { id: 2, src: 'photo2.jpg', title: 'Photo 2' },\n      { id: 3, src: 'photo3.jpg', title: 'Photo 3' },\n      { id: 4, src: 'photo4.jpg', title: 'Photo 4' },\n    ];\n    \n    function initGallery() {\n      const gallery = document.getElementById('gallery');\n      gallery.innerHTML = photos.map(photo =&gt; `\n        &lt;div class=\"gallery-item\" data-id=\"${photo.id}\"&gt;\n          &lt;img src=\"${photo.src}\" alt=\"${photo.title}\"&gt;\n        &lt;\/div&gt;\n      `).join('');\n      \n      gallery.addEventListener('click', (e) =&gt; {\n        const item = e.target.closest('&#91;data-id]');\n        if (item) {\n          selectPhoto(parseInt(item.dataset.id));\n        }\n      });\n      \n      \/\/ Display first photo\n      selectPhoto(1);\n    }\n    \n    function selectPhoto(photoId) {\n      const photo = photos.find(p =&gt; p.id === photoId);\n      if (!photo) return;\n      \n      if (document.startViewTransition) {\n        document.startViewTransition(() =&gt; {\n          displayPhoto(photo);\n        });\n      } else {\n        displayPhoto(photo);\n      }\n    }\n    \n    function displayPhoto(photo) {\n      const display = document.getElementById('photoDisplay');\n      display.innerHTML = `\n        &lt;img src=\"${photo.src}\" alt=\"${photo.title}\"&gt;\n        &lt;h2&gt;${photo.title}&lt;\/h2&gt;\n      `;\n    }\n    \n    \/\/ Initialize when page loads\n    document.addEventListener('DOMContentLoaded', initGallery);\n  &lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Resources and Further Reading<\/h2>\n\n\n\n<p>If you want to dive deeper:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/View_Transitions_API\">MDN Web Docs: View Transitions API<\/a><\/strong> \u2014 The full technical reference. It&#8217;s solid documentation.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/developer.chrome.com\/docs\/web-platform\/view-transitions\/\">Chrome Developers: View Transitions<\/a><\/strong> \u2014 Official guides and more examples<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/caniuse.com\/view-transitions\">Can I Use: View Transitions<\/a><\/strong> \u2014 Check current browser support in real time<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/jakearchibald.com\/\">Jake Archibald&#8217;s Blog<\/a><\/strong> \u2014 Jake&#8217;s posts on View Transitions are excellent. He goes deep.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/www.w3.org\/TR\/css-view-transitions-1\/\">W3C CSS View Transitions Module<\/a><\/strong> \u2014 The actual specification if you really want to understand how it works<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">In Summary<\/h2>\n\n\n\n<p>The View Transitions API isn&#8217;t revolutionary in the sense that it does something that was impossible before. But it&#8217;s revolutionary in accessibility. It takes something that was hard and makes it trivial. It takes something that required expertise and opens it up to everyone.<\/p>\n\n\n\n<p>Here&#8217;s what actually matters:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You can create smooth animations in 3 lines of code instead of dozens<\/li>\n\n\n\n<li>Browser support is actually pretty good right now<\/li>\n\n\n\n<li>You can use it today with proper fallbacks<\/li>\n\n\n\n<li>As browser support improves, your users automatically get better experiences<\/li>\n<\/ul>\n\n\n\n<p>The web is slowly becoming more polished. Interactions are getting smoother. Users are coming to expect that polish. View Transitions are a huge part of why that&#8217;s happening.<\/p>\n\n\n\n<p>If you&#8217;re building web applications, you should be using them. Not because they&#8217;re cutting-edge or trendy, but because they&#8217;re practical, they work, and they make your users&#8217; experiences better with minimal effort on your part.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><\/h2>\n","protected":false},"excerpt":{"rendered":"<p>How a new browser feature is making smooth animations accessible to everyone If you&#8217;ve ever visited a modern website and noticed how smoothly photos expand when you click on them, or how elegantly content slides into view, you&#8217;ve experienced the magic of web animations. Until recently, creating these polished effects required complicated code and specialist [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-113","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/posts\/113","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/comments?post=113"}],"version-history":[{"count":5,"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/posts\/113\/revisions"}],"predecessor-version":[{"id":142,"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/posts\/113\/revisions\/142"}],"wp:attachment":[{"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/media?parent=113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/categories?post=113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/luca05.co.uk\/article\/wp-json\/wp\/v2\/tags?post=113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}