Skip to content

Instantly share code, notes, and snippets.

@DanRibbens
Last active July 13, 2023 07:25
Show Gist options
  • Save DanRibbens/00dc9e971b0df9f58c3726885a2a59aa to your computer and use it in GitHub Desktop.
Save DanRibbens/00dc9e971b0df9f58c3726885a2a59aa to your computer and use it in GitHub Desktop.
Angular applications load and replace the `<app-root>` element of the index.html file. Before the browser has had a chance to load and execute the js and css bundles of your app, you may want to show a loading indicator. For a recent project where angular material was being used, it made sense to want to show the same spinner loader that fit the…

Angular Material indeterminate spinner for index.html of angular app

Description

Angular applications load and replace the <app-root> element of the index.html file. Before the browser has had a chance to load and execute the js and css bundles of your app, you may want to show a loading indicator. For a recent project where angular material was being used, it made sense to want to show the same spinner loader that fit the rest of the app. Because the angular app is still loading it was necessary to copy the styles and some markup to the index.html of the app to show the spinner before our app was ready. This file is the result of copying the markup of the spinner and removing angular material markup that isn't necessary when working outside of angular.

Credit & Links

There is very little original work here, mostly I copied the markup and styles from the browser inspector from the angular material spinner of a loaded application. Angular Components https://github.com/angular/components

This is where the original styling code is written: https://github.com/angular/components/blob/9.2.x/src/material/progress-spinner/progress-spinner.scss

<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet" />
<link rel="icon" type="image/x-icon" href="./assets/favicon.ico" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Your Application</title>
<base href="/" />
</head>
<body>
<app-root>
<style>
.center {
position: absolute;
top: calc(50vh - 50px);
left: calc(50vw - 50px);
}
.mat-progress-spinner {
animation: mat-progress-spinner-linear-rotate 2s linear infinite;
display: block;
position: relative;
height: 100px;
width: 100px;
}
.mat-progress-spinner svg {
position: absolute;
transform: rotate(-90deg);
top: calc(50% - 50px);
left: calc(50% - 50px);
transform-origin: center;
overflow: visible;
}
.mat-progress-spinner svg circle {
animation-name: mat-progress-spinner-stroke-rotate-100;
stroke: #3f51b5;
stroke-dasharray: 282.743px;
stroke-width: 10%;
transition-property: stroke;
animation-duration: 4000ms;
animation-timing-function: cubic-bezier(0.35, 0, 0.25, 1);
animation-iteration-count: infinite;
fill: transparent;
transform-origin: center;
transition: stroke-dashoffset 225ms linear;
}
@keyframes mat-progress-spinner-linear-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes mat-progress-spinner-stroke-rotate-100 {
0% {
stroke-dashoffset: 268.606171575px;
transform: rotate(0);
}
12.5% {
stroke-dashoffset: 56.5486677px;
transform: rotate(0);
}
12.5001% {
stroke-dashoffset: 56.5486677px;
transform: rotateX(180deg) rotate(72.5deg);
}
25% {
stroke-dashoffset: 268.606171575px;
transform: rotateX(180deg) rotate(72.5deg);
}
25.0001% {
stroke-dashoffset: 268.606171575px;
transform: rotate(270deg);
}
37.5% {
stroke-dashoffset: 56.5486677px;
transform: rotate(270deg);
}
37.5001% {
stroke-dashoffset: 56.5486677px;
transform: rotateX(180deg) rotate(161.5deg);
}
50% {
stroke-dashoffset: 268.606171575px;
transform: rotateX(180deg) rotate(161.5deg);
}
50.0001% {
stroke-dashoffset: 268.606171575px;
transform: rotate(180deg);
}
62.5% {
stroke-dashoffset: 56.5486677px;
transform: rotate(180deg);
}
62.5001% {
stroke-dashoffset: 56.5486677px;
transform: rotateX(180deg) rotate(251.5deg);
}
75% {
stroke-dashoffset: 268.606171575px;
transform: rotateX(180deg) rotate(251.5deg);
}
75.0001% {
stroke-dashoffset: 268.606171575px;
transform: rotate(90deg);
}
87.5% {
stroke-dashoffset: 56.5486677px;
transform: rotate(90deg);
}
87.5001% {
stroke-dashoffset: 56.5486677px;
transform: rotateX(180deg) rotate(341.5deg);
}
100% {
stroke-dashoffset: 268.606171575px;
transform: rotateX(180deg) rotate(341.5deg);
}
}
</style>
<div class="center">
<div role="progressbar" class="mat-progress-spinner" style="width: 100px; height: 100px;">
<svg focusable="false" style="width: 100px; height: 100px;">
<circle cx="50%" cy="50%" r="45"></circle>
</svg>
</div>
</div>
</app-root>
</body>
</html>
@cichy380
Copy link

You forgot about stroke property in .mat-progress-spinner svg circle selector. Without this the spinner is invisible until angular styles are ready.

@DanRibbens
Copy link
Author

Thanks @cichy380!
I've updated it to include the default material theme color.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment