⮌ back | Overview | Home

🎷The Swing Animation

The swing animation is an animation that rotates the content of a transition group. For live examples visit the animation demo page and select one of the swing presets in the button grid at the top of the page.

Contents

Why would I use this component?

Astro allows users to create their own animations for view transitions. The astro-vtbot swing animation is a ready-made solution that can be easily inserted into Astro’s transition:animate property. It also supports parameters for fine-tuning the animation to your needs. It is even possible to customize the underlying keyframes when used together with the <AnimationStyle/> component.

Usage

Install astro-vtbot in your project running npx astro add astro-vtbot or npm install astro-vtbot.

Basic usage

The most basic usage is to apply the swing() animation without any parameters. This will use the default values for the animation.

MyComponent.astro
---
import { swing } from "astro-vtbot/animations/swing";
---
...
<h1 transition:animate={swing()}>Swing</h1>
...

The effect will rotate the old-image 90° around the y axis. When it completely vanished, the animation for the new-image kicks in and again rotates 90° back to the full view. The animation will take 0.15 seconds and use the ease-in-out easing function.

❗ Perspective

Please note that 3D-effects require the CSS perspective property to be set on a parent of the transformed element.

For browsers that natively support view transition good choices for that parent are the ::view-transition-group or ::view-transition-image-pair pseudo element, which is the parent of the ::view-transition-old and ::view-transition-new pseudo elements.

animation.css
::view-transition-image-pair(*) {
perspective: 50cm;
}

The animations offered by the Bag of Tricks generate this for you, so you are already save on browsers that natively support view transitions.

For browsers that do not natively support view transitions, there are no such pseudo elements. For Astro’s fallback mode for view transitions to work properly with 3D animations, you have to set the perspective on a regular HTML element that is a parent of the animated element in the DOM.

Here is how this is done in the animation demo:

AnimationMdxLayout.astro
...
<div style="perspective: 50cm">
<div id="demo">
<a href="./#">Flip</a>
<slot />
<br style="clear:both" />
</div>
</div>
...

Clipping

The same applies to clipping: To support browsers that do not implement native view transitions, set overflow to clip on a parent element in the DOM. For browsers that support native view transitions, set it to the ::view-transition-group or ::view-transition-image-pair pseudo-elements. Unlike perspective, overflow is not set by default as it is not clear whether you want clip or visible. In future versions you may be able to set this with a parameter.

AnimationMdxLayout.astro
...
<div style="perspective: 50cm; overflow: clip">
<div id="demo">
...
</div>
</div>
<style>
::view-transition-image-pair(*) {
overflow: clip;
}
<style>

Parametrized usage

The default values for the animation can be overwritten by passing an object with the desired values to the swing() function. The following example shows how to change the duration and easing of the animation.

MyComponent.astro
---
import { swing } from "astro-vtbot/animations/swing";
---
...
<h1 transition:animate={swing({duration:'1.5s', easing: 'cubic-bezier(.16,.73,.05,1.52)' })}>Swing</h1>
...

You can set the following parameters:

Property nameCSS propertyDefault value
durationanimation-duration0.15s
easinganimation-timing-functionease-in-out
delayanimation-delay(see below)
directionanimation-directionnormal
fillModeanimation-fill-modeboth

The default value for delay is 0 for the out-animation of the old image. If not specified, the delay for the in-animation of the new image uses the duration value. The in-animation therefore begins as soon as the out-animation is complete. If you explicitly set a value for the delay, this value is used for both the in and out animation. This is typically not what you want. If you want to use different values for the in and out animation, use the customSwing function as described in the next section.

Extended parametrized usage

If you want to use more than the 5 properties supported by swing() or want to have more control over the animations keyframes, you can use the customSwing() function. This function takes a name for the transition and an object with the following optional properties:

The function returns a scope identifier to be used with the data-astro-transition-scope attribute of the HTML element you want to animate. Under the hood, customSwing() generates a style sheet with keyframe information and the defined CSS properties. You need to add these extended styles to your page by using the <AnimationStyle/> component. Note: Only use <AnimationStyle/> in conjunction with customSwing(), not with swing().

MyComponent.astro
---
import { customSwing } from "astro-vtbot/animations/swing";
import AnimationStyle from "astro-vtbot/animations/AnimationStyle.astro";
const swingScope = customSwing('mySwing', {
keyframes: { axis: { y: 1 }, angle: { leave: '90deg', shrink: '-90deg' } },
base: { duration: '300ms' },
extensions: {
forwards: {
old: { 'transform-origin': 'center left' },
new: { 'transform-origin': 'center right', 'animation-delay': '0.075s' },
},
backwards: {
old: { 'transform-origin': 'center right' },
new: { 'transform-origin': 'center left', 'animation-delay': '0.075s' },
},
},
});
---
...
<AnimationStyle name="mySwing"/>
<h1 data-astro-transition-scope={swingScope}>Swing</h1>
...

Keyframes

The keyframes object of the customSwing() function has the following properties:

type SwingKeyframeParameter = {
axis?: { x?: number; y?: number; z?: number; };
angle?: { leave?: string; enter?: string; };
opacity?: { mid?: number; to?: number; };
};

The default values are all 0 with the exception of

The values are used as parameters of the keyframe definition in

this style sheet template
Swing.css.template
@keyframes ${keyframeNamePrefix}FwdSwingOut {
from {
transform: rotate3d(${x}, ${y}, ${z}, 0);
opacity: 1;
}
50% {
opacity: ${midOpacity};
}
to {
transform: rotate3d(${x}, ${y}, ${z}, ${leaveAngle});
opacity: ${toOpacity};
}
}
@keyframes ${keyframeNamePrefix}FwdSwingIn {
from {
transform: rotate3d(${x}, ${y}, ${z}, ${enterAngle});
opacity: ${toOpacity};
}
50% {
opacity: ${midOpacity};
}
to {
transform: rotate3d(${x}, ${y}, ${z}, 0);
opacity: 1;
}
}
@keyframes ${keyframeNamePrefix}BwdSwingOut {
from {
transform: rotate3d(${x}, ${y}, ${z}, 0);
opacity: 1;
}
50% {
opacity: ${midOpacity};
}
to {
transform: rotate3d(${x}, ${y}, ${z}, ${enterAngle});
opacity: ${toOpacity};
}
}
@keyframes ${keyframeNamePrefix}BwdSwingIn {
from {
transform: rotate3d(${x}, ${y}, ${z}, ${leaveAngle});
opacity: ${toOpacity};
}
50% {
opacity: ${midOpacity};
}
to {
transform: rotate3d(${x}, ${y}, ${z}, 0);
opacity: 1;
}
}
::view-transition-image-pair(*) {
perspective: 50cm;
}

Base

The value of the base property is used to call the swing() function as defined above.

Extensions

With the extensions property you can define all those CSS properties that can not be defined by swing() directly. You can specify different values for forwards and backwards, in and out animations. These values are merged with the result of callingswing() with base parameters and overwrite its properties.