Make Your Landing Page Smooth as Butter with ng-animate

Hello,

Today I want to talk about something I have seen on some sites that I am really fond of: the smooth fade-in animation upon page load. You may have seen something similar around the web.

This effect can be done in a number of ways. We can use CSS, Angular built-in animations, and various libraries. One library in particular that I’ve been using for awhile is ng-animate:

https://www.npmjs.com/package/ng-animate

Today we’re going to use this library for our own application. We will make a landing page for a language exchange platform called Global Gab. We want to add a header, some web statistics, and four picture tiles to display the different options that users can select.

Skill Prerequisites

  • Fundamental HTML and CSS/SCSS knowledge
  • Experience with Angular 2+ and TypeScript
  • Familiarity with Angular Material components
  • Knowledge of Angular animations

Source Code

If you want to skip the tutorial and get the complete project, clone it here:

https://github.com/LucyVeron/sleek-fade

Procedure

Ok, if you’ve been following my blog you know the drill. First let’s make sure we have the latest Node and npm installed on our system. Download them here:

Next we’ll set up our Angular project. Install the Angular CLI tool:

npm install -g @angular/cli

Generate a new project:

ng new sleek-page

Change into the newly-created project directory:

cd sleek-page

Add Angular Material:

ng add @angular/material

Run the local dev server:

ng serve

Check localhost:4200 in your browser:

localhost:4200

Ok, the next step is to create a simple landing page. We’ll write up some logic in the component file first:

app.component.ts

import { Component } from '@angular/core';

export interface Option {
  text: string;
  image: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  public options: Option[] = [
    {
      text: 'Find language tutors',
      image: '../assets/tutor.jpg'
    },
    {
      text: 'Find exchange partners',
      image: '../assets/exchange.jpg'
    },
    {
      text: 'Blog Community',
      image: '../assets/blogger.jpg'
    },
    {
      text: 'Language Events',
      image: '../assets/event.jpg'
    }
  ];
}

We are creating four Options representing each tile:

  • Find language tutors
  • Find exchange partners
  • Blog community
  • Language events

Each of these Options include the aformentioned text and a photo (HINT: you can find these pictures from my repository, or you may choose to include your own).

Now we’ll replace the default HTML with the following template:

app.component.html

<div class="container">
  <div class="headline">Global Gab</div>
  <div class="stats">
    <h3>40+ Languages</h3>
    <h3>10,000+ users</h3>
    <h3>500+ tutors</h3>
  </div>
  <div class="options">
    <div class="option" *ngFor="let opt of options">
      <img [src]="opt.image">
      <div>{{opt.text}}</div>
    </div>
  </div>
</div>

…and finally, add some style:

app.component.scss

.container {
  display: flex;
  flex-direction: column;
  margin: 1rem;
  & .headline {
    text-align: center;
    font-size: 100px;
    font-weight: lighter;
  }
  & .stats {
    display: flex;
    justify-content: space-between;
    width: 1300px;
    margin: auto;
    color: orangered;
  }
  & .options {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    & .option {
      width: 300px;
      height: 300px;
      margin: 1rem;
      & img {
        width: 100%;
        height: 100%;
      }
      & div {
        text-align: center;
      }
    }
  }
}
@media only screen and (max-width: 1362px) {
  .container .stats {
    width: unset;
    margin: 0 10rem;
  }
}
@media only screen and (max-width: 770px) {
  .container .stats {
    display: flex;
    flex-direction: column;
    text-align: center;
  }
}

Notice that we’ve included media queries to optimize the view for mobile, tablet, and desktop.

That’s about it for the landing page. Check the development server for the result:

localhost:4200

Now let’s add some animations. First install ng-animate:

npm install ng-animate --save

If you don’t have the Browser Animations Module already, add it to the imports because we will need it to make the animations work:

app.module.ts

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
...
@NgModule({
...  
  imports: [
    ...
    BrowserAnimationsModule
  ],

We’ll combine the capabilities of ng-animate with the animation functionality provided by Angular. The ng-animate animations will greatly simplify our logic.

To demonstrate this difference in complexity, here is an example of a regular Angular animation:

animations: [
    trigger('pageAnimations', [
      transition(':enter', [
        query('.hero, form', [
          style(
          { opacity: 0,
            transform: 'translateY(-100px)'
          }),
          stagger(-30, [
            animate(
            '500ms cubic-bezier(0.35, 0, 0.25, 1)',
            style(
            { opacity: 1,
              transform: 'none'})
            )
          ])
        ])
      ])
    ])
  ]

…and the same with ng-animate:

  animations: [
    trigger('pageAnimations', [
      transition(':enter', [
        query('.hero, form', [
          style({ opacity: 0 }),
          stagger(-30, [
            useAnimation(fadeInDown),
            style({ opacity: 1 })
          ])
        ])
      ])
    ])
  ]

We’ll go ahead and perform the final step of adding the animation:

app.component.ts

import { query, stagger, style, transition, trigger, useAnimation } from '@angular/animations';
import { Component, HostBinding } from '@angular/core';
import { fadeInDown } from 'ng-animate';

export interface Option {
  text: string;
  image: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  animations: [
    trigger('staggerText', [              // Animation name
      transition(':enter', [              // Initial page load    
        query(
          '.headline, .stats, .option', [ // Apply to these classes
          style({ opacity: 0 }),          // Elements start invisible
          stagger(-100, [                 // Delay of 100ms
            useAnimation(fadeInDown),     // imported from ng-animate
            style({ opacity: 1 })         // Show elements 100%
          ])
        ])
      ])
    ])
  ]
})
export class AppComponent {

  @HostBinding('@staggerText')

  public options: Option[] = [
    {
      text: 'Find language tutors',
      image: '../assets/tutor.jpg'
    },
    {
      text: 'Find exchange partners',
      image: '../assets/exchange.jpg'
    },
    {
      text: 'Blog Community',
      image: '../assets/blogger.jpg'
    },
    {
      text: 'Language Events',
      image: '../assets/event.jpg'
    }
  ];
}

Basically we’re applying staggered animations (one after another) to three elements. They will initially be invisible, slowly drop down, and end with 100% opacity. This creates a “fade” effect. There is a slight delay between each “fade-in” which adds a touch of elegance to the animation.

The @HostBinding() decorator allows you to apply the animation to the component’s base HTML instead of the inner HTML found in app.component.html.

Alright, that is it! We’ve spruced up our ordinary landing page with some sleek animations. Check out the result in the dev server:

If you like this feature and want to experiment and learn more, you can check out all the animations at ng-animate’s demo page:

https://jiayihu.github.io/ng-animate/

Happy animating!

Latest Posts

2 Comments

Leave a comment