Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

View transitions 3.0 changes #4320

Merged
merged 21 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 123 additions & 40 deletions src/content/docs/en/guides/view-transitions.mdx
Original file line number Diff line number Diff line change
@@ -1,50 +1,26 @@
---
title: View Transitions (Experimental)
title: View Transitions
description: >-
How to enable experimental support for view transitions in your Astro site.
Enable seamless navigation between pages in Astro, with view transitions.
i18nReady: true
---

import Since from '~/components/Since.astro'

Support for **opt-in, per-page, view transitions** in Astro projects can be enabled behind an experimental flag. View transitions update your page content without the browser's normal, full-page navigation refresh and provide seamless animations between pages.
Astro supports **opt-in, per-page, view transitions** with just a few simple APIs. View transitions update your page content without the browser's normal, full-page navigation refresh and provide seamless animations between pages.

Astro provides a `<ViewTransitions />` routing component that can be added to a single page's `<head>` to control page transitions as you navigate away to another page. It provides a lightweight client-side router that intercepts navigation and allows you to customize the transition between pages. Add this component to a reusable `.astro` component, such as a common head or layout, for animated page transitions across your entire site (SPA mode).

Astro's view transitions support is powered by the new [View Transitions](https://developer.chrome.com/docs/web-platform/view-transitions/) browser API and also includes:

- A few [built-in animations](#built-in-animation-directives), such as `slide` and `fade`.
- A few [built-in animations](#built-in-animation-directives), such as `fade`, `slide`, and `none`.
- Support for both forwards and backwards navigation animations.
- The ability to fully [customize all aspects of transition animation](#customizing-animations), and build your own animations.
- [Control over fallback behavior](#fallback-control) for browsers that do not yet support the View Transition APIs.

:::caution
View transitions is an experimental feature enabled in Astro 2.9. The API is subject to change before it is marked as stable.
:::

## Enabling View Transitions in your Project

You can enable support for animated page transitions through the experimental `viewTransitions` flag in your Astro config:

```js title="astro.config.mjs" ins={4-6}
import { defineConfig } from 'astro/config';

export default defineConfig({
experimental: {
viewTransitions: true
}
});
```

:::note
Enabling view transitions support does not automatically convert your entire site into a SPA (Single-page App). By default, every page will still use regular, full-page, browser navigation.

Add page transitions in Astro with the `<ViewTransitions />` routing component on a per-page basis, or site-wide.
:::

## Full site view transitions (SPA mode)

Import and add the `<ViewTransitions />` component to your common `<head>` or shared layout component. Astro will create default page animations based on the similiarities between the old and new page, and will also provide fallback behavior for unsupported browsers.
Import and add the `<ViewTransitions />` component to your common `<head>` or shared layout component. Astro will create default page animations based on the similarities between the old and new page, and will also provide fallback behavior for unsupported browsers.

The example below shows adding view transitions site-wide by importing and adding this component to a `<CommonHead />` Astro component:

Expand Down Expand Up @@ -130,24 +106,26 @@ As a convenient shorthand, `transition:persist` can alternatively take a transit

## Built-in Animation Directives

Astro comes with a few built-in animations to override the default `morph` transition. Add the `transition:animate` directive to try Astro's `slide` or `fade` transitions.
Astro comes with a few built-in animations to override the default `fade` transition. Add the `transition:animate` directive to customize the behavior of your transitions.

- `morph` (default): The browser determines the best way to animate the element depending on how similar the pages are. For example, if the element is positionally different between pages, it will appear to float to its new position. If the element is in the exact same position, it will appear to not move at all.
- `fade` (default): An opinionated crossfade animation, where the old content fades out and the new content fades in.
- `initial`: Opt out of Astro's opinionated crossfade animation and use the browser's default styling.
- `none`: Disable the browser's default animations. This value can be used on a page's `<html>` element to disable the default fade.
- `slide`: An animation where the old content slides out to the left and new content slides in from the right. On backwards navigation, the animations are the opposite.
- `fade`: A cross-fade where the old content fades out and the new content fades in.

The example below produces a slide animation for the body content while keeping a positionally-identical header in place:
The example below produces a slide animation for the body content while disabling the browser's fade animation for the rest of the page:

```astro
---
import { CommonHead } from '../components/CommonHead.astro';
---
<html>

<html transition:animate="none">
<head>
<CommonHead />
</head>
<body>
<header> // defaults to transition:animate="morph"
<header>
...
</header>
<main transition:animate="slide">
Expand Down Expand Up @@ -244,9 +222,33 @@ import { ViewTransitions } from 'astro:transitions';
```

:::note[known limitations]
The `morph` animation cannot be simulated in traditional CSS. So any element using this animation will not be animated.
The `initial` browser animation is not simulated by Astro. So any element using this animation will not currently be animated.
:::

## Navigation steps

When using the `<ViewTransitions />` router, the following steps are performed as part of navigation:

1. The user triggers navigation by either:
- Click a `<a>` to another page in your site.
- Clicking the back button.
- Clicking the forward button.
2. The router starts fetching the next page.
3. The router adds the `data-astro-transition` attribute to the HTML element with a value of `'forward'` or `'back'` depending on whether it is back navigation or not.
4. The router calls `document.startViewTransition`. This triggers the browser's own [view transition process](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API#the_view_transition_process). Importantly the browser screenshots the current state of the page.
5. Inside the `startViewTransition` callback, the router performs a __swap__.
1. The contents of the `<head>` are swapped out.
- Stylesheet DOM nodes are left in if they exist on the new page, to prevent FOUC.
- Scripts are left in if they exist on the new page.
- Any other head elements with `transition:persist` are left in if there is a corresponding element in the new page.
2. The `<body>` is completely replaced with the new page's body.
3. Elements marked `transition:persist` are moved over to the new DOM if they exist on the new page.
4. Scroll position is restored if necessary.
5. The `astro:after-swap` event is triggered on the `document`. This is the end of the __swap__ process.
6. The router waits for any new stylesheets to load before resolving the transition.
7. The router executes any new scripts added to the page.
8. The `astro:page-load` event fires. This is the end of the navigation process.

## Script behavior during page navigation

When navigating between pages with the `<ViewTransitions />` component, scripts are run in sequential order to match browser behavior.
Expand All @@ -263,7 +265,7 @@ If you have code that sets up global state, this state will need to take into ac

Module scripts are only ever executed once because the browser keeps track of which modules are already loaded. For these scripts, you do not need to worry about re-execution.

### `astro:load`
### `astro:page-load`

An event that fires at the end of page navigation, after the new page is visible to the user and blocking styles and scripts are loaded. You can listen to this event on the `document`.

Expand All @@ -273,14 +275,14 @@ You can use this event to run code on every page navigation, or only once ever:

```astro "{ once: true }"
<script>
document.addEventListener('astro:load', () => {
document.addEventListener('astro:page-load', () => {
// This only runs once.
setupStuff();
}, { once: true });
</script>
```

### `astro:beforeload`
### `astro:after-swap`

An event that fires immediately after the new page replaces the old page. You can listen to this event on the `document`.

Expand All @@ -299,10 +301,91 @@ For example, if you are implementing dark mode support, this event can be used t
// Runs on initial navigation
setDarkMode();
// Runs on view transitions navigation
document.addEventListener('astro:beforeload', setDarkMode);
document.addEventListener('astro:after-swap', setDarkMode);
</script>
```

## `prefers-reduced-motion`

Astro's `<ViewTransitions />` component includes a CSS media query that disables *all* view transition animations, including fallback animation, whenever the [`prefer-reduced-motion`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) setting is detected. Instead, the browser will simply swap the DOM elements without an animation.

## Preventing client-side navigation

Once you have enabled client-side routing on a page by adding the `<ViewTransitions />` component, every anchor on the page that links to another page on your site will be navigated via client-side routing. There are some cases where you might want to not navigate via CSR. One example is if the link is to any non-page, such as a PDF within your `public/` folder. Or an API route that produces an image.

In these cases you can opt-out of client-side routing on a per-link basis using the `data-astro-reload` attribute like so:

```html
<a href="/quarterly-earnings.pdf" data-astro-reload>
```

These links will be ignored by the router and a full page navigation will occur.

## Upgrade to v3.0 from v2.x

View transitions are no longer behind an experimental flag in Astro v3.0.

These and other accompanying changes may cause some breaking changes when you upgrade your Astro project from an earlier version.

Please follow the instructions below as appropriate to upgrade an Astro v2.x project to v3.0.

### Upgrade from `experimental.viewTransitions`

If you had previously enabled the experimental flag for view transitions, you will need to update your project for Astro v3.0 which now allows view transitions by default.

#### Remove `experimental.viewTransitions` flag

Remove the experimental flag:

```js title="astro.config.mjs" del={4-6}
import { defineConfig } from 'astro/config';

export default defineConfig({
experimental: {
viewTransitions: true
}
});
```

#### Update `transition:animate` directives

The `transition:animate` value `morph` has been renamed to `initial`. Also, this is no longer the default animation.

```astro title="src/components/MyComponent.astro" del="morph" ins="initial"
<div transition:name="MyComponent" transition:animate="morph initial" />
```

If no `transition:animate` directive is specified, your animations will now default to `fade`.

```astro title="src/components/MyComponent.astro" del="transition:animate=\"fade\""
<div transition:name="MyComponent" transition:animate="fade" />
```

Astro also supports a new `transition:animate` value, `none`. This value can be used on a page's `<html>` element to disable animated full-page transitions on an entire page.

```astro ins="transition:animate=\"none\""
<html transition:animate="none">
<head></head>
<body>
<h1>Hello world!</h1>
</body>
</html>
```

#### Update event names

The event `astro:load` has been renamed to `astro:page-load`.

```astro title="src/components/MyComponent.astro" del="astro:load" ins="astro:page-load"
<script>
document.addEventListener('astro:load astro:page-load', runSetupLogic);
</script>
```

The event `astro:beforeload` has been renamed to `astro:after-swap`.

```astro title="src/components/MyComponent.astro" del="astro:beforeload" ins="astro:after-swap"
<script>
document.addEventListener('astro:beforeload astro:after-swap', setDarkMode);
</script>
```
2 changes: 1 addition & 1 deletion src/i18n/en/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export default [
{ text: 'Middleware', slug: 'guides/middleware', key: 'guides/middleware' },
{ text: 'Testing', slug: 'guides/testing', key: 'guides/testing' },
{
text: 'View Transitions (Experimental)',
text: 'View Transitions',
slug: 'guides/view-transitions',
key: 'guides/view-transitions',
},
Expand Down