Staggered Animation in Ionic Angular

April 17th 2020 Ionic 4+ Angular

Recently, Josh Morony published an interesting tutorial about staggered animations in Ionic. Since he's using StencilJS, there are some syntax changes required to make his sample code work with Angular. It wasn't as trivial as I expected.

Staggered animation

His approach is based on CSS variables that are set in individual list items:

<ion-list lines="none">
  <ion-item style="--animation-order: 0">
    <ion-label>One</ion-label>
  </ion-item>
  <ion-item style="--animation-order: 1">
    <ion-label>Two</ion-label>
  </ion-item>
  <ion-item style="--animation-order: 2">
    <ion-label>Three</ion-label>
  </ion-item>
  <ion-item style="--animation-order: 3">
    <ion-label>Four</ion-label>
  </ion-item>
  <ion-item style="--animation-order: 4">
    <ion-label>Five</ion-label>
  </ion-item>
</ion-list>

The value of the variable is then used in CSS to parameterize the animation-delay:

ion-item {
  animation: popIn 0.2s calc(var(--animation-order) * 70ms) both ease-in;
}

@keyframes popIn {
  0% {
    opacity: 0;
    transform: scale(0.6) translateY(-8px);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

Of course, list items usually aren't hardcoded. Hence, a binding must be used to set the correct value to the CSS variable. Unfortunately, the ngStyle directive doesn't work with CSS variables:

<ion-list lines="none">
  <ion-item *ngFor="let item of items; index as i"
            [ngStyle]="{'--animation-order': i}">
    <ion-label>{{item}}</ion-label>
  </ion-item>
</ion-list>

Neither does style binding:

<ion-list lines="none">
  <ion-item *ngFor="let item of items; index as i"
            [style.--animation-order]="i">
    <ion-label>{{item}}</ion-label>
  </ion-item>
</ion-list>

I found a workaround for that in a related GitHub issue:

<ion-list lines="none">
  <ion-item *ngFor="let item of items; index as i"
      [attr.style]="sanitizer.bypassSecurityTrustStyle('--animation-order: ' + i)">
    <ion-label>{{item}}</ion-label>
  </ion-item>
</ion-list>

DomSanitizer must be injected into the page for this to work:

constructor(public sanitizer: DomSanitizer) {}

If you're using Ionic 5, you can update your project to Angular 9. This will allow you to use style binding syntax:

<ion-list lines="none">
  <ion-item *ngFor="let item of items; index as i"
            [style.--animation-order]="i">
    <ion-label>{{item}}</ion-label>
  </ion-item>
</ion-list>

However, even in Angular 9, the ngStyle directive still doesn't support CSS variables.

The full source code for the sample project is available in a Bitbucket repository.

This blog post is a part of a series of posts about animations in Ionic.

Get notified when a new blog post is published (usually every Friday):

Copyright
Creative Commons License