GibboK
GibboK

Reputation: 74008

Alternative to keyframes in CSS?

I need to create a loading spinner, at the moment I am using the following code.

I would like to know if is possible to rewrite it using an alternative syntax for keyframes (maybe transitions?).

Unfortunately I am using a build tool which rewrite keyframes properties adding bugs and the CSS generated is not working so I would like to work around the problem.

A JS solution is also possible, adding CSS inline.

.loadingSpinner {
    width: 50px;
    height: 50px;
    border: 5px solid #3498db;
    border-top-color: rgba(0, 0, 0, 0);
    border-left-color: rgba(0, 0, 0, 0);
    border-radius: 50%;
    -moz-animation: loadingSpinner 0.7s infinite linear;
    -o-animation: loadingSpinner 0.7s infinite linear;
    -webkit-animation: loadingSpinner 0.7s infinite linear;
    animation: loadingSpinner 0.7s infinite linear;
}

@-moz-keyframes loadingSpinner {
  0%   {
      -moz-transform: rotate(0deg);

  }
  100% {
      -moz-transform: rotate(360deg);
  }
}

@-o-keyframes loadingSpinner {
  0%   {
      -o-transform: rotate(0deg);

  }
  100% {
      -o-transform: rotate(360deg);
  }
}

@-webkit-keyframes loadingSpinner {
  0%   {
      -webkit-transform: rotate(0deg);

  }
  100% {
      -webkit-transform: rotate(360deg);
  }
}

@keyframes loadingSpinner {
  0%   {
      transform: rotate(0deg);

  }
  100% {
      transform: rotate(360deg);
  }
}
<div class="loadingSpinner"></div>

Upvotes: 5

Views: 3433

Answers (3)

Rounin
Rounin

Reputation: 29521

You can create an infinite CSS transition using a single CSS Custom Property, the value of which you can update every time the JavaScript transitionend event fires.

In the CSS stylesheet, we can start with the following transform and transition:

  transform: var(--rotation);
  transition: transform 0.7s linear;

We will need to initialise --rotation, so we can do that at the top of the stylesheet:

:root {
  --rotation: rotate(0deg);
}

So far, so good. Now we need a JS function which moves the rotation value up by 360deg every time the transition completes:

const rotateSpinner = () => {

  let loadingSpinnerStyles = window.getComputedStyle(loadingSpinner);
  let rotation = loadingSpinnerStyles.getPropertyValue('--rotation');
  rotation = parseInt(rotation.replace('rotate(', '').replace('deg)', '')) + 360;
  rotation = 'rotate(' + rotation + 'deg)';
  loadingSpinner.style.setProperty('--rotation', rotation);
}

When we put everything together, we get the working example below.


Working Example:

const loadingSpinner = document.querySelector('.loadingSpinner');

const rotateSpinner = () => {

  let loadingSpinnerStyles = window.getComputedStyle(loadingSpinner);
  let rotation = loadingSpinnerStyles.getPropertyValue('--rotation');
  rotation = parseInt(rotation.replace('rotate(', '').replace('deg)', '')) + 360;
  rotation = 'rotate(' + rotation + 'deg)';
  loadingSpinner.style.setProperty('--rotation', rotation);
}

loadingSpinner.addEventListener('transitionend', rotateSpinner);
window.addEventListener('load', rotateSpinner);
:root {
  --rotation: rotate(0deg);
}

.loadingSpinner {
  width: 50px;
  height: 50px;
  border: 5px solid #3498db;
  border-top-color: rgba(0, 0, 0, 0);
  border-left-color: rgba(0, 0, 0, 0);
  border-radius: 50%;
  transform: var(--rotation);
  transition: transform 0.7s linear;
}
<div class="loadingSpinner"></div>

Upvotes: 0

MKAD
MKAD

Reputation: 457

what about only css solution?

@keyframes spinner {
    to {transform: rotate(360deg);}
}
 
@-webkit-keyframes spinner {
    to {-webkit-transform: rotate(360deg);}
}
 
.spinner {
    min-width: 30px;
    min-height: 30px;
}
 
.spinner:before {
    content: 'Loading…';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 50px;
    height: 50px;
    margin-top: -13px;
    margin-left: -13px;
}
 
.spinner:not(:required):before {
    content: '';
    border-radius: 50%;
    border: 5px solid #ccc;
    border-top-color: #03ade0;
    animation: spinner .7s linear infinite;
    -webkit-animation: spinner .7s linear infinite;
}
<div class="spinner"></div>

Upvotes: 0

ezakto
ezakto

Reputation: 3194

You could use a very long transition and trigger it with a quick js line. For example, add a .start class that triggers a 60 second transition that rotates the spinner several times (for example, 36000deg).

.loadingSpinner {
    width: 50px;
    height: 50px;
    border: 5px solid #3498db;
    border-top-color: rgba(0, 0, 0, 0);
    border-left-color: rgba(0, 0, 0, 0);
    border-radius: 50%;
    transform: rotate(0deg);
    transition: transform 60s;
}

.loadingSpinner.start {
    transform: rotate(36000deg);
}

Example: https://jsfiddle.net/6tkf1f95/1/

Upvotes: 3

Related Questions