Previously, it was difficult to achieve smooth transitions while navigating the web. Compatibility, performance, and accessibility seemed unattainable because we had to juggle SPA, JavaScript, and CSS. Thankfully, the new native browser API view transitions and Astro implementation have made this process easier. Astro handles the heavy lifting, reduces CSS and JavaScript overhead, and provides true navigation through multi-page applications (MPAs).
This guide will walk you through building a basic shop so you can use this technique to navigate smoothly between pages.
If you’re interested in learning how to build an entire website using Astro, we recommend the following: Astro 3.0 course Written by James Q. This is a practical course that teaches you how to build websites using Astro 3.0, an all-in-one framework for the modern web. Codrops readers receive a special 10% discount:
Start
Clone a GitHub repository
If you want to get started quickly, check out our Github repository.
step by step
First, create an Astro project using the installer. If you run into any issues or have questions, our Astro installation guide has all the answers.
# Using NPM
npm create astro@latest
# Using Yarn
yarn create astro
# Using PNPM
pnpm create astro@latest
During installation, the installer will prompt you for several settings.please choose empty Use project options as a starting point.
Understand folder structure
- component: This folder contains various components such as buttons, cards, etc.
- Layout: Now save your shared page layout.
- page: This folder contains pages and navigation is based on file-based routing. For more information, please see the Astro Routing Guide.
Astro supports various UI frameworks such as React, Vue, and Svelte. This demo uses Astro syntax to create components. These files have a .astro extension and combine HTML, CSS, and JS.
TailwindCSS integration
This project uses TailwindCSS for styling. Include this using the Astro CLI.
# Using NPM
npx astro add tailwind
# Using Yarn
yarn astro add tailwind
# Using PNPM
pnpm astro add tailwind
Product data
This example uses a data set for products containing sports shoes and shirts, but feel free to use whatever data you want.
These images are already optimized for the web, so put them in the /publics folder. By default, Astro does not optimize images in public folders. If you want Astro to optimize them, you need to put them in the /src folder or configure them. Learn more about Astro image optimization
Add icon library
This example uses astro-icon as the page icon.
# Using NPM
npm i astro-icon
# Using Yarn
yarn add astro-icon
# Using PNPM
pnpm add astro-icon
Running the project
# Using NPM
npm run dev
# Using Yarn
yarn dev
# Using PNPM
pnpm dev
A blank page will appear.
layout and design
First, create a layout for the entire page.Found below src/layouts/Layout.astro
By default, Astro renders pages statically at build time, so you’ll see three dashes at the top of the page. This separates the JavaScript that is executed at build time (or when requesting SSR, etc.) from the rest. page.
---
import ViewTransitions from "astro:transitions";
interface Props
title: string;
description?: string;
const
title,
description = "A simple Shop built in Astro using View Transitions and TailwindCSS",
= Astro.props;
---
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description" content=description />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content=Astro.generator />
<title>title - Astro Transitions Shop</title>
<ViewTransitions />
</head>
<body>
<main
class="relative max-w-6xl min-h-screen mx-auto py-6 lg:pt-10 px-4 pb-20"
>
<slot />
</main>
<style is:global>
:root
body
background-color: theme(colors.gray.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 solid #ffffff;
@keyframes animate-in
0%
opacity: 0;
transform: translateY(1rem);
100%
opacity: 1;
transform: translateY(0);
</style>
</body>
</html>
To use view transitions,
The layout expects the following title and explanation Get properties from child elements. However, you can set any properties you want, such as metadata props.
has also been introduced. <メイン> A tag that centers the page’s content.of <スロット /> The tag is where Astro inserts the layout’s child components, similar to React’s “children” prop.
At the bottom, <スタイル:グローバル> Use tags to declare global styles shared by this layout. In this example, we defined a style for the browser scrollbar and a simple keyframe animation for the title when transitioning to the product page.
home page
Next, let’s create a homepage consisting of a header and product list.It can be found at src/pages/index.astro.
---
import Layout from "../layouts/Layout.astro";
import products from "../data";
import ProductCard from "../components/ProductCard.astro";
---
<Layout title="Shop">
<div class="flex gap-3 items-end">
<h1 class="text-4xl font-bold">Astro Shop</h1>
</div>
<h3 class="text-xl text-gray-500">
Take a look in our products, feel free to buy some
</h3>
<div class="flex flex-wrap justify-center sm:justify-normal gap-4 py-8">
products.map((product) => <ProductCard product />)
</div>
</Layout>
What we import is <レイアウト> Assign a title to the previously created component. We are also extracting products from previously created product data. <プロダクトカード /> This is the next component to create.
product card
Product cards are components designed to display our products in a list. Used Tailwind to apply common styles to ensure product images, titles, descriptions, and prices display correctly.
Found below src/components/ProductCard.astro.
---
import type Product from "../data";
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.cover
alt=product.name
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.name
</h3>
<p
class="text-gray-600 text-sm truncate"
>
product.description
</p>
<div class="text-right mt-4">
<span class="font-semibold">$product.price</span>
</div>
</div>
</article>
</a>
ProductCard is product props and rendering <記事> within This is a tag for navigation. In Astro, navigation is tag with href Attribute pointing to the desired page.
Product page
The product page is a dynamic page named . [slug] This corresponds to the product’s slug defined in the product data.
The product page can be found at: src/page/product/[slug]/index.astro.
---
import type Product, products from "../../../data";
import Layout from "../../../layouts/Layout.astro";
import ProductCard from "../../../components/ProductCard.astro";
import Icon from "astro-icon";
const slug = Astro.params;
export function getStaticPaths()
return [
...products.map((product) => (
params:
slug: product.slug,
,
)),
];
const product = products.find((product) => product.slug === slug) as Product;
---
<Layout
title=product.name
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 name="mdi:chevron-left" class="h-6 w-6" /></a
>
<div class="flex gap-2 pb-2 items-center text-gray-500">
<a class="after:content-['/'] after:pl-2 capitalize" href="/">home</a>
<span class="after:content-['/'] after:pl-2 capitalize"
>product.category</span
>
<span>product.name</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.cover
alt=product.name
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.name
</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.price
</div>
<div class="text-xs text-gray-500">* This is a fictional price</div>
<button
type="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">Similar products</h4>
<div class="flex flex-wrap justify-center sm:justify-normal gap-4">
products
.filter((p) => p.category === product.category && p.id !== product.id)
.map((pr) => <ProductCard product=pr />)
</div>
</div>
</Layout>
On this page, slug Gets the prop from the navigation Params and exports a function named. getStaticPaths. Astro uses this feature to generate static pages (SSG) for his website and create pages for all his products. /products/[slug]
Format such as /product/haryo-setyadi-shirt
.
In the product title, .animate-in A class that animates the title when entering the page. At the bottom you get similar products based on category.
Note that this example utilizes SSG, so the page will be generated at build time. If you need to retrieve data at request time, you should use SSR. To learn more about SSG and SSR, check out Astro Docs.
Implementing view transitions
Next, implement view transitions between the pages you created. To do this, Transition: Name Attributes the elements that animate during transitions between pages. Let’s examine the layout in more detail.
- in home pageEach product card Features image, title, explanationand price.
- Similarly, Product page will also be displayed image, title, explanationand price For each product.
To implement a smooth transition between two pages, you must link elements on both pages using unique links. transition name. That way, Astro’s view transitions will automatically handle the animation during navigation.
Step 1: Assign transition:name to elements in the product card
Modify the element in the product card so that the transition name matches the element on the product page.
- src/components/ProductCard.astro
Product card image
...
<img
src=product.cover
alt=product.name
transition:name=`$product.slug image`
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:name=`$product.slug title`
>
product.name
</h3>
...
Product card description
...
<p
class="text-gray-600 text-sm truncate"
transition:name=`$product.slug description`
>
product.description
</p>
...
product card price tag
...
<div class="text-right mt-4" transition:name=`$product.slug price`>
<span class="font-semibold">$product.price</span>
</div>
...
It is important to note that we are assigning a transition name that is a combination of the product slug and the element’s name.This allows each Transition names are unique within a pageThis allows Astro to seamlessly link and animate between them during navigation.
Step 2: Link transition:name to the corresponding element on the product page
Follow the same steps to associate appropriate transition names with relevant elements on this page to ensure a smooth transition experience.
- /src/page/product/[slug]/index.astro
Product page image
...
<img
src=product.cover
alt=product.name
class="w-full h-full object-cover rounded-xl shadow-2xl shadow-gray-200 border-b"
transition:name=`$slug image`
/>
...
Product page title
...
<h1 class="text-3xl sm:text-5xl font-bold animate-in">
product.name
</h1>
<div transition:name=`$slug title`></div>
...
transition name
Large title elements, such as , may cause unusual sliding behavior in view transitions. Assigning this to an adjacent element will ensure a smooth transition of the product card title. This workaround addresses a current limitation, which may be resolved in a future update.
Product page description
...
<p
class="max-w-sm py-4 text-lg"
transition:name=`$slug description`
>
product.description
</p>
...
Product page price
...
<div class="text-3xl font-semibold" transition:name=`$slug price`>
$product.price
</div>
...
...
<p
class="max-w-sm py-4 text-lg"
transition:name=`$slug description`
>
product.description
</p>
...
...
<div class="text-3xl font-semibold" transition:name=`$slug price`>
$product.price
</div>
...
Use consistent transition names and refer to corresponding components for seamless transitions.
Thus, it is completed! As you navigate, you’ll see attractive sliding animations between pages.
Browser support and accessibility
View transitions still work experimental features It is not yet widely supported. For a comprehensive understanding, please check the browser compatibility table.
Astro offers: Fallback for unsupported browsers For this feature, prefers shrinking motion setting.
Astro sets fallback animations by default for unsupported browsers. If you observe unusual behavior in these environments, consider deactivating the fallback.
For more information, customize animation and Configuring fallback See the Astro View transition documentation.
Design choices for view transitions
On mobile devices, transitions often appear more subtle due to the limited screen size. Conversely, on larger screens, animations can appear exaggerated or overly intense, which can detract from the user’s experience. As this example shows, a good design approach is to simplify and expand elements. Therefore, it is important that view transitions match your design choices.
The Astro team is actively working to improve these transitions and give you more control over their animations.
performance
Another important aspect to consider is performance. While web browsers continually optimize for better performance, profiling your website is essential to identifying and addressing excessive animations.
Final considerations
The view transitions combined with Astro integration are definitely impressive. However, it should be carefully considered before deploying to a production app. The appropriateness of using view transitions depends on the nature of your application and its audience. For example, if your page has a complex UI, this feature may not be optimal. Nevertheless, view transitions have great potential to improve the user experience on numerous websites.
Full screen image slideshow animation ideas
Gradually enhanced WebGL lens refraction