4.9 C
New York
Friday, January 12, 2024

Animating Multi-Web page Navigations with Browser View Transitions and Astro


Earlier, reaching a clean transition whereas navigating on the net was difficult. We needed to juggle SPA, JavaScript, and CSS, which made compatibility, efficiency, and accessibility appear unattainable. Fortunately, with the brand new Native Browser API View Transitions and the Astro implementation, this course of is now easy. Astro takes care of the heavy lifting, decreasing the CSS and JavaScript overhead and providing true navigation through Multi Web page Software (MPA).

On this information, we’ll stroll by constructing a primary store, profiting from this method to make sure clean transitions between pages.

Getting began

Cloning the GitHub repository

In the event you’re desperate to get began, take a look at the Github repository.

Step-by-step

Start by creating an Astro undertaking utilizing its installer. In the event you encounter any points or have questions, the Astro Set up Information has all of the solutions.

# Utilizing NPM
npm create astro@newest
# Utilizing Yarn
yarn create astro
# Utilizing PNPM
pnpm create astro@newest

Throughout set up, the installer will immediate you for some settings. Select the Empty undertaking possibility as your start line.

Understanding the Folder Construction

  • parts: This folder incorporates numerous parts like buttons, playing cards, and many others.
  • layouts: Right here, we retailer shared web page layouts.
  • pages: This folder incorporates pages, and navigation is predicated on file-based routing. Uncover extra about this within the Astro Routing Information.

Astro helps quite a lot of UI frameworks similar to React, Vue, Svelte, and extra. For this demonstration, we’ll use the Astro Syntax to create our parts. These recordsdata have an .astro extension and mix HTML, CSS, and JS.

Integrating TailwindCSS

We’ll make the most of TailwindCSS for styling on this undertaking. Use the Astro CLI to include it:

# Utilizing NPM
npx astro add tailwind
# Utilizing Yarn
yarn astro add tailwind
# Utilizing PNPM
pnpm astro add tailwind

Merchandise Knowledge

For this instance, we shall be utilizing an information set of Merchandise that incorporates some sport sneakers and shirts, however be happy to make use of any knowledge you need.

We’ll place these photographs within the /publics folder since they’re already optimized for the online. By default, Astro is not going to optimize photographs within the public’s folder. If you’d like Astro to optimize them, it is best to put them within the /src folder or configure it. Study extra about Astro Picture Optimization

Add an icon library

On this instance, we are going to use astro-icon for the web page icons.

# Utilizing NPM
npm i astro-icon
# Utilizing Yarn
yarn add astro-icon
# Utilizing PNPM
pnpm add astro-icon

Operating the undertaking

# Utilizing NPM
npm run dev
# Utilizing Yarn
yarn dev
# Utilizing PNPM
pnpm dev

You’ll see a clean web page.

Format and Design

First, create an general structure for the pages. Will probably be positioned below src/layouts/Format.astro

Astro defaults render the web page statically throughout construct time, so on the prime of the web page, we see three dashes — that separate the JavaScript that shall be executed throughout construct time (or through the request time for SSR, for instance) from the remainder of the web page.

---
import { ViewTransitions } from "astro:transitions";
interface Props {
  title: string;
  description?: string;
}

const {
  title,
  description = "A easy Store in-built Astro utilizing View Transitions and TailwindCSS",
} = Astro.props;
---

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta identify="description" content material={description} />

    <meta identify="viewport" content material="width=device-width" />
    <hyperlink rel="icon" kind="picture/svg+xml" href="/favicon.svg" />
    <meta identify="generator" content material={Astro.generator} />
    <title>{title} - Astro Transitions Store</title>
    <ViewTransitions />
  </head>
  <physique>
    <most important
      class="relative max-w-6xl min-h-screen mx-auto py-6 lg:pt-10 px-4 pb-20"
    >
      <slot />
    </most important>

    <fashion is:world>
      :root {
      }
      physique {
        background-color: theme(colours.grey.50);
      }
      .animate-in {
        animation: animate-in 0.5s ease-in-out;
      }
      /* Firefox */
      * {
        scrollbar-width: auto;
        scrollbar-color: #c7c7c7 #ededed;
      }

      /* Chrome, Edge, and Safari */
      *::-webkit-scrollbar {
        width: 15px;
      }

      *::-webkit-scrollbar-track {
        background: #ededed;
      }

      *::-webkit-scrollbar-thumb {
        background-color: #c7c7c7;
        border-radius: 5px;
        border: 2px strong #ffffff;
      }
      @keyframes animate-in {
        0% {
          opacity: 0;
          rework: translateY(1rem);
        }
        100% {
          opacity: 1;
          rework: translateY(0);
        }
      }
    </fashion>
  </physique>
</html>

To make use of View Transitions, we have to import and place the <ViewTransitions /> element throughout the <head> part of the structure we wish to use. As soon as performed, you’ll observe that navigation has adopted a fade impact.

The structure expects the title and description properties from its little one parts. Nevertheless, you may set any properties you need, similar to metadata props, as an example.

We’ve additionally launched a <most important> tag that may centrally place our web page content material. The <slot /> tag is the place Astro will inject the kid parts of the structure, much like the ‘kids’ prop in React.

On the backside, we use the <fashion is:world> tag to declare world kinds shared by this structure. On this instance, we’ve outlined kinds for the browser’s scrollbar and a easy keyframe animation for the title when transitioning to the product web page.

The house web page

Let’s now create our residence web page, which is able to comprise the header and the merchandise record. It may be discovered at src/pages/index.astro.

---
import Format from "../layouts/Format.astro";
import { merchandise } from "../knowledge";
import ProductCard from "../parts/ProductCard.astro";
---

<Format title="Store">
  <div class="flex gap-3 items-end">
    <h1 class="text-4xl font-bold">Astro Store</h1>
  </div>
  <h3 class="text-xl text-gray-500">
    Have a look in our merchandise, be happy to purchase some
  </h3>
  <div class="flex flex-wrap justify-center sm:justify-normal gap-4 py-8">
    {merchandise.map((product) => <ProductCard {product} />)}
  </div>
</Format>

We’re importing the <Format /> element we beforehand created and assigning a title to it. We’re additionally extracting merchandise from our merchandise knowledge that was created earlier, and we’ll be utilizing the <ProductCard /> element, which we are going to create subsequent.

Product Card

The product card is a element designed to show our product within the record. I’ve utilized some common styling utilizing Tailwind to make sure the Product Picture, Title, Description, and Value are offered accurately.

Astro shop card example

It’s positioned below src/parts/ProductCard.astro.

---
import kind { Product } from "../knowledge";

interface Props {
  product: Product;
}

const { product } = Astro.props;
---

<a href={`/product/${product.slug}`} class="block">
  <article
    class="group bg-flex flex-col sm:w-60 w-72 bg-white shadow-sm rounded-lg overflow-hidden hover:shadow-xl hover:shadow-gray-100 transition-all"
  >
    <div class="sm:w-60 w-72 h-60 overflow-hidden">
      <img
        src={product.cowl}
        alt={product.identify}
        class="object-cover object-center w-full grayscale-[0.1] group-hover:grayscale-0 h-full rounded-md group-hover:scale-105 transition-all"
      />
    </div>
    <div class="p-4">
      <h3
        class="font-semibold truncate"
      >
        {product.identify}
      </h3>
      <p
        class="text-gray-600 text-sm truncate"
      >
        {product.description}
      </p>
      <div class="text-right mt-4">
        <span class="font-semibold">${product.value}</span>
      </div>
    </div>
  </article>
</a>

The ProductCard expects a product prop and renders an <article> inside an <a> tag for navigation. In Astro, navigation may be merely achieved by utilizing an <a> tag with the href attribute pointing to the specified web page.

Product Web page

The Product web page is a dynamic web page named [slug] that corresponds to the product’s slug outlined in our merchandise knowledge.

astro shop product page

The Product web page shall be positioned at src/pages/product/[slug]/index.astro.

---
import { kind Product, merchandise } from "../../../knowledge";
import Format from "../../../layouts/Format.astro";
import ProductCard from "../../../parts/ProductCard.astro";
import Icon from "astro-icon";
const { slug } = Astro.params;

export perform getStaticPaths() {
  return [
    ...products.map((product) => ({
      params: {
        slug: product.slug,
      },
    })),
  ];
}

const product = merchandise.discover((product) => product.slug === slug) as Product;
---

<Format
  title={product.identify}
  description={product.description}
>
  <div class="max-w-5xl mx-auto relative">
    <a
      href="/"
      class="absolute xl:-left-14 top-8 xl:-top-1 xl:bg-none bg-gradient-to-br from-gray-100 rounded p-2 z-10"
      ><Icon identify="mdi:chevron-left" class="h-6 w-6" /></a
    >
    <div class="flex gap-2 pb-2 items-center text-gray-500">
      <a category="after:content-['/'] after:pl-2 capitalize" href="/">residence</a>
      <span class="after:content-['/'] after:pl-2 capitalize"
        >{product.class}</span
      >
      <span>{product.identify}</span>
    </div>
    <div class="flex flex-col md:flex-row sm sm:gap-8">
      <div class="max-w-[450px] w-full h-full max-h-[450px]">
        <img
          src={product.cowl}
          alt={product.identify}
          class="w-full h-full object-cover rounded-xl shadow-2xl shadow-gray-200 border-b"
        />
      </div>
      <article class="py-4 flex justify-between flex-col">
        <div>
          <h1 class="text-3xl sm:text-5xl font-bold animate-in">
            {product.identify}
          </h1>
          <p
            class="max-w-sm py-4 text-lg"
          >
            {product.description}
          </p>
        </div>
        <div class="pt-2 sm:pt-8 text-right">
          <div class="text-3xl font-semibold">
            ${product.value}
          </div>
          <div class="text-xs text-gray-500">* It is a fictional value</div>
          <button
            kind="button"
            class="mt-4 px-5 py-2 bg-gray-900 hover:bg-gray-800 text-white font-semibold rounded-full"
            >Add to cart</button
          >
        </div>
      </article>
    </div>
    <div class="py-6 md:py-20 max-w-3xl">
      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Incidunt magnam
      quia, explicabo dolor velit aut omnis natus consequatur possimus fuga illo
      commodi asperiores dignissimos. Consequuntur nam quae commodi quas, magni
    </div>
    <h4 class="font-bold text-lg">Related merchandise</h4>
    <div class="flex flex-wrap justify-center sm:justify-normal gap-4">
      {
        merchandise
          .filter((p) => p.class === product.class && p.id !== product.id)
          .map((pr) => <ProductCard product={pr} />)
      }
    </div>
  </div>
</Format>

For this web page, we anticipate the slug prop from the navigation Params and export a perform named getStaticPaths. Astro makes use of this perform to generate static pages (SSG) for our web site, creating pages for each product within the /merchandise/[slug] format, similar to /product/haryo-setyadi-shirt.

Within the product title, we use the .animate-in class to animate the title when getting into the web page. On the backside, we fetch comparable merchandise primarily based on their class.

Word that this instance makes use of SSG, so pages are generated at construct time. In the event you want knowledge fetched at request time, it is best to use SSR. Study extra about SSG and SSR within the Astro Docs.

Implementing View Transitions

We’re now going to implement View Transitions between the pages we’ve created. To do that, we have to add the transition:identify attribute to the weather that we wish to animate throughout transitions between pages. Let’s look at our structure in additional element.

  • On the residence web page, every product card options an Picture, Title, Description, and Value.
  • Equally, the product web page additionally shows the Picture, Title, Description, and Value for every product.

To implement clean transitions between the 2 pages, we have to hyperlink the weather on each pages utilizing a novel Transition Title. By doing so, Astro’s View Transitions will robotically deal with the animations throughout navigation.

Step 1: Assigning transition:identify to Parts within the Product Card

We’ll modify the weather inside our Product Card to make sure their transition names align with these on the Product Web page.

  • src/parts/ProductCard.astro

Product Card Picture

...
      <img
        src={product.cowl}
        alt={product.identify}
        transition:identify={`${product.slug} picture`} 
        class="object-cover object-center w-full grayscale-[0.1] group-hover:grayscale-0 h-full rounded-md group-hover:scale-105 transition-all"
      />
...

Product Card Title

...
      <h3
        class="font-semibold truncate"
        transition:identify={`${product.slug} title`}
      >
        {product.identify}
      </h3>
...

Product Card Description

...
      <p
        class="text-gray-600 text-sm truncate"
        transition:identify={`${product.slug} description`}
      >
        {product.description}
      </p>
...

Product Card Value Tag

...
      <div class="text-right mt-4" transition:identify={`${product.slug} value`}>
        <span class="font-semibold">${product.value}</span>
      </div>
...

It’s important to notice that we’ve assigned the transition identify combining the product’s slug with the identify of the factor. This ensures that every transition identify is exclusive throughout the web page, permitting Astro to seamlessly hyperlink and animate between them throughout navigation.

Step 2: Hyperlink transition:identify to Corresponding Parts on the Product Web page

Following the identical process, we’ll affiliate the suitable transition names to the related parts on this web page, making certain a clean transition expertise.

  • /src/pages/product/[slug]/index.astro

Product Web page Picture

...
        <img
          src={product.cowl}
          alt={product.identify}
          class="w-full h-full object-cover rounded-xl shadow-2xl shadow-gray-200 border-b"
          transition:identify={`${slug} picture`}
        />
...

Product Web page Title

...
          <h1 class="text-3xl sm:text-5xl font-bold animate-in">
            {product.identify}
          </h1>
          <div transition:identify={`${slug} title`}></div>
...

It’s value noting that we assigned the transition identify to a <div> adjoining to the <h1> title factor reasonably than to the title itself. At occasions, View Transitions can exhibit uncommon slide behaviors with bigger title parts like <h1>. By assigning it to a neighboring factor, we guarantee a smoother transition for the product card title. This workaround addresses present limitations, which can be addressed in future updates.

Product Web page Description

...
          <p
            class="max-w-sm py-4 text-lg"
            transition:identify={`${slug} description`}
          >
            {product.description}
          </p>
...

Product Web page Value

...
          <div class="text-3xl font-semibold" transition:identify={`${slug} value`}>
            ${product.value}
          </div>
...

We’ve used constant transition names, making certain they reference the corresponding parts for a seamless transition.

And similar to that, it’s performed! Upon navigation, you’ll now expertise a charming slide animation between the pages.

Browser Assist and Accessibility

View Transitions stays an experimental characteristic and doesn’t get pleasure from widespread assist but. For a complete understanding, assessment the browser compatibility chart.

Astro gives a fallback for browsers that lack assist for this characteristic, and it additionally respects the prefers-reduced-motion setting.

Astro defaults to a fallback animation for unsupported browsers. In the event you observe uncommon conduct in these environments, you may think about deactivating the fallback.

For extra details about customizing the animation and configuring the fallback see the Astro View Transitions Documentation

Design Decisions for View Transitions

On cellular units, transitions typically seem extra delicate because of the restricted display screen dimension. Conversely, on bigger screens, animations can come throughout as exaggerated or overly intense, which can result in a compromised consumer expertise. A very good design method is to simplify and enlarge parts, as demonstrated on this instance. Thus, it’s important that your View Transitions align along with your design selections.

The Astro group is actively working to refine these transitions and supply better management over animations.

Efficiency

One other essential facet to contemplate is efficiency. Whereas internet browsers regularly optimize for higher efficiency, it’s important to profile your web site to determine and handle any extreme animations.

Last Concerns

View Transitions, mixed with Astro integration, are undeniably spectacular. Nevertheless, cautious consideration is required earlier than deploying them in manufacturing apps. The appropriateness of utilizing View Transitions hinges on the character of your utility and its goal customers. As an illustration, in case your web page has a fancy UI, this characteristic won’t be the very best match. Nonetheless, View Transitions maintain huge potential for enhancing the consumer expertise on quite a few web sites.



Supply hyperlink

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles