14 Feb 2024 · Software Engineering

    Seamless SPA Transitions Using the New View Transitions API (Part 1)

    10 min read
    Contents

    Have you ever wondered why web applications can’t have the same smooth visual transitions as native mobile apps? Single-page applications (SPAs) have transformed our web interactions with dynamic content loading that eliminates the jarring full-page refresh. Yet, they often fall short in delivering the polished, seamless transitions we enjoy on our mobile devices.

    The View Transitions API is here to fill that void. It’s not just an incremental update; it’s a leap forward, promising to bring the fluidity of mobile transitions to the web.

    In this piece, we’ll explore the View Transitions API, its innovative features and how to integrate them into your web projects.

    Brief Overview of SPAs and the Need for Smooth Transitions

    At its core, SPAs are web applications that load a single HTML page and dynamically update that page as the user interacts with the app. This architecture has become a cornerstone of modern web development, enabling the creation of fast, responsive sites that don’t require the user to endure the stop-and-start experience of traditional web page loading.

    However, despite their speed and responsiveness, SPAs have often fallen short in one critical area: the art of transition. The shift from one view to another in SPAs has traditionally been instantaneous and, at times, disorienting—lacking the visual cues that guide users through their journey on native platforms. The need for smooth transitions between multiple parts of a SPA cannot be understated as it has several importances such as:

    • Visual Continuity: Smooth transitions help maintain visual continuity, which is key to understanding the flow of interactions within the application.
    • User Expectation: Users have come to expect seamless transitions as part of a polished and modern web experience, similar to what they experience on mobile apps.
    • Reduced Cognitive Load: Transitions that mimic the natural flow of tasks reduce cognitive load, making it easier for users to follow and predict application behavior.
    • Feedback and Confirmation: They act as feedback for user actions, confirming that an input has been received and processed by the system.
    • Enhanced Aesthetics: Smooth transitions contribute to the aesthetic appeal of the application, which can be a crucial factor in user satisfaction and retention.

    Introduction to the View Transitions API

    The View Transitions API is a web standard that enables developers to create smooth, performant transitions between different states of an application’s view. It operates by capturing snapshots of the DOM at different stages and interpolating between them, thus providing a more immersive user experience.

    How it Differs from Traditional Transition Methods

    Traditional web transitions often depend on CSS animations or JavaScript-driven effects, which can be cumbersome to implement and may suffer from performance issues on complex or resource-intensive animations.

    On the other hand, the View Transitions API stands out by offering a more streamlined and systematized approach. It allows developers to define intricate animations in a more declarative fashion, with the browser optimizing performance under the hood.

    This means less manual work for developers and a smoother user experience, with the added benefit of reducing the code needed to create these effects.

    How The View Transition API Works

    The View Transitions API is designed to facilitate the creation of smooth and animated transitions between different states of the Document Object Model (DOM) in a web application. This is particularly useful in enhancing user experience by providing a visual continuity that helps users maintain their context when the content changes dynamically, such as in single-page applications.

    Here’s a step-by-step explanation of how the View Transitions API works:

    1. Initiating a Transition: When document.startViewTransition() is called, the API captures a screenshot of the current view of the page. This screenshot will serve as the “old” state during the transition.
    2. Updating the DOM: The callback function passed to startViewTransition() is then executed. This function is responsible for making the necessary changes to the DOM, such as updating content, which will be reflected in the “new” state after the transition.
    3. Capturing the New State: Once the callback has completed its DOM updates, the API takes a live representation of the new state of the page.
    4. Creating Pseudo-elements: The API constructs a pseudo-element tree consisting of several pseudo-elements which include:
    ::view-transition
            └─::view-transition-group(root)
             └─::view-transition-image-pair(root)
                ├─::view-transition-old(root)
                └─::view-transition-new(root)
    • :view-transition: The container element for other pseudo-elements.
    • ::view-transition-group: Responsible for animating the size and position between the two states.
    • ::view-transition-image-pair: Holds the screenshot of the old and new states.
    • ::view-transition-old(root): Holds the screenshot of the previous state
    • ::view-transition-new(root): Holds the representation of the new state

    These pseudo-elements can be styled with CSS properties similar to other visual elements like images or videos.

    1. Running the Transition: The default transition is a cross-fade effect where the old view fades out (opacity goes from 1 to 0) and the new view fades in (opacity goes from 0 to 1). This creates a smooth visual change from the old to the new content.
    2. Customizing Transitions: Developers can customize transitions using the view-transition-name CSS property to apply different animations to specific elements. Additionally, default animations can be overridden with custom CSS animations or JavaScript, providing a high degree of flexibility in how transitions are presented.
    3. Controlling with JavaScript: The** ViewTransition** object returned by startViewTransition() contains promises that allow developers to execute code at different stages of the transition, such as when the transition is ready to start or after it has finished.

    Getting Started with the View Transitions API

    Browser Support Check

    Before diving into the implementation, it’s crucial to check for browser support, as the API is relatively new and may not be available in all browsers. Use a tool like CanIUse to check for browser support.

    Basic Setup and Prerequisites

    To get started, ensure that your SPA framework is compatible with the API and that you have a basic understanding of JavaScript promises, as they are integral to the API’s operation.

    To use the View Transitions API, you first need to enable it on your browser. You may not have both of these flags on your system – it’s enough to just enable one or the other. For Chrome, type in **chrome://flags/ **on the search bar and enable this feature.

    You can also find the complete source code here on GitHub.

    Implementing the View Transitions API in a SPA

    Starting with a straightforward example, we’ll create a smooth fade-out transition between two pieces of UI.

    1. Setting Up the Page MockupOn our main page, we have two children elements containing distinct data (image and text) concerning each child.
    <div class="animals__list">
      <div class="animal__container">
        <img src="./dog.jpg" alt="Dog" />
        <div class="animal__text">
          <p>
            <strong> Dogs:</strong> Dogs are known for their strong sense of smell,
            and they have up to 300 million olfactory receptors in their noses,
            compared to about 5-6 million in humans. This remarkable sense of smell
            allows them to detect scents, track trails, and even identify medical
            conditions in some cases.
          </p>
          <button class="show__cat">Show Cat</button>
        </div>
      </div>
      <div class="animal__container hidden">
        <img src="./cat.jpg" alt="Cat" />
        <div class="animal__text">
          <p>
            <strong> Cats:</strong> Cats have retractable claws, which is a unique
            feature that sets them apart from many other animals. These sharp claws
            are useful for hunting, climbing, and defending themselves. When a cat
            is at rest or walking, their claws are retracted to keep them sharp, but
            they can extend them when needed for various tasks.
          </p>
          <button class="show__dog">Show Dog</button>
        </div>
      </div>
    </div>
    1. Defining the transition using CSS pseudo-elementsIn order to specify the duration of the transition, we use the view-transition CSS property to smoothly transition between changes.
    ::view-transition-old(root),
    ::view-transition-new(root) {
      animation-duration: 1s;
    }
    
    1. Selecting DOM elementsNext, we select all the elements required to perform the transition.
    document.addEventListener("DOMContentLoaded", () => {
      const showCatButton = document.querySelector(".show__cat");
      const showDogButton = document.querySelector(".show__dog");
      const dogContainer = document.querySelector(
        ".animal__container:not(.hidden)"
      );
      const catContainer = document.querySelector(".animal__container.hidden");
    });
    1. Using the View Transition APIThen, we use the startViewTransition function to conditionally toggle the visibility between both children elements.
    // Function to handle the transition
    function switchAnimal(showElement, hideElement) {
      if (document.startViewTransition) {
        document.startViewTransition(() => {
          hideElement.classList.add("hidden");
          showElement.classList.remove("hidden");
        });
      } else {
        // Fallback if View Transitions API is not supported
        hideElement.classList.add("hidden");
        showElement.classList.remove("hidden");
      }
    }
    1. Attaching Event Listeners

    Finally, we add event listeners to both buttons for seamless transition.

    // Event listener for the 'Show Cat' button
    showCatButton.addEventListener("click", () => {
      switchAnimal(catContainer, dogContainer);
    });
    
    // Event listener for the 'Show Dog' button
    showDogButton.addEventListener("click", () => {
      switchAnimal(dogContainer, catContainer);
    });

    Here’s our final result:

    Source code: GitHub

    Transitioning multiple elements

    In the previous demo, the entire UI is involved in the shared transition, but that doesn’t always have to be the case. In the event we want to transition elements separately, say the text transition different from the image, it can be achieved using the view-transition-name property on the element.

    .animal__text {
      view-transition-name: animal-header;
    }
    • Then we create the animation for the target element using CSS keyframes.
    @keyframes fade-in {
      from {
        opacity: 0;
      }
    }
    
    @keyframes fade-out {
      to {
        opacity: 0;
      }
    }
    
    @keyframes slide-from-right {
      from {
        transform: translateY(30px);
      }
    }
    
    @keyframes slide-to-left {
      to {
        transform: translateY(-30px);
      }
    }
    
    ::view-transition-old(animal-header) {
      animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out, 300ms cubic-bezier(
            0.4,
            0,
            0.2,
            1
          ) both slide-to-left;
    }
    
    ::view-transition-new(animal-header) {
      animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in, 300ms
          cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
    }

    Here’s our final result:

    Source code: GitHub

    Potential Challenges

    While the View Transition API is a tempting feature to always reach for when building SPA, it is important to note some of its drawbacks.

    • Finding Balance with Transitions: Transitions can make your website feel alive and engaging. But just like spices when cooking, too much of it can spoil the experience. It’s important to use them in a way that feels natural and helps users use your site, not just for fancy effects.
    • Keeping Your Site Accessible: When you add transitions, remember that not everyone experiences your site in the same way. Some people might find moving elements confusing or distracting, especially if they have difficulties with motion or vision. So, it’s crucial to make sure that your transitions don’t get in the way of anyone using your site.

    As an added measure you should disable animations for users who have opted out of them in their settings.

    @media (prefers-reduced-motion) {
      ::view-transition-group(*),
      ::view-transition-old(*),
      ::view-transition-new(*) {
        animation: none !important;
      }
    }
    • Testing for Everyone: Make sure to test your transitions to see that they work well for all users, including those who might need to use screen readers or other assistive tools. If a transition is too much, users should have the option to turn it off or skip it. This way, you keep your site welcoming for everyone.

    Conclusion

    The View Transitions API marks a significant milestone in web development, offering a path to more engaging and visually appealing SPAs. As developers, it’s an exciting time to explore the capabilities of this API and push the boundaries of what’s possible on the web. Let’s embrace this new tool to create experiences that are not just functional but also delightful to interact with.

    One thought on “Seamless SPA Transitions Using the New View Transitions API (Part 1)

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    David Herbert
    Writen by:
    David is a front-end developer by day and a technical writer by night, who enjoys breaking down complex topics into comprehensible bits digestible to even 5-year-olds.
    Avatar
    Reviewed by:
    I picked up most of my soft/hardware troubleshooting skills in the US Army. A decade of Java development drove me to operations, scaling infrastructure to cope with the thundering herd. Engineering coach and CTO of Teleclinic.