Ged Kirkham

JavaScript - Python - HTML - CSS

creating a refresh button with javascript and css animation

published 2019/11/19

introduction

i want to provide a visual cue to the user once they have clicked a button to give confidence that a process is currently in progress due to their action. i want to do this without large text based notifications, and wanted it to look slick. at the time, the only thing that i found was an animation that appeared inside the button, and then slowly faded away once the action was complete. to me, this looked cheap, so i went about making my own.

animation and keyframes

to use css animation, you must first specify a keyframe. keyframes hold the style(s) the element will have at specified times, and we can determine this with the from and to parameters. when you specify css styles inside the @keyframes rule, the animation will gradually change from the current, to the new style.

setup

you must first bind the animation to an element. to do this, simply provide the @keyframe with a title, and then assign that title to the element's class/id via animation-name property. i did this by assigning a @keyframe to the .refresh-start class.

@keyframes rotate {

from {transform: rotate(0deg)}
to {transform: rotate(360deg)}

}


.refresh-start {

animation-name: rotate;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-play-state: running;

}

when the above two css properties are applied to the below code, we get the following effect.

<button>refresh <img class="refresh-start" src="../img/refresh-icon.svg" height="12" /></button>



from the above code, you should be able to see that there is a keyframe titled rotate assigned to the .refresh-start class. the from keyframe property employs the transform property that enables us to determine a starting point for our svg icon - 0deg. the to keyframe property also employs the transform property and determines that the element will end at 360deg - one full rotation.

starting the animation

the current animation looks good, but i only want it to animate once the user has clicked the button. to achieve this effect, i will need to dynamically manipulate the dom.

firstly, add an onclick event to the <button> that triggers a function - refreshContent(). add an id titled refresh-button to the <button>, and an id titled refresh-icon to the <img>.

<button id="refresh-button" class="refresh-end" onclick="refreshContent()">refresh <img id="refresh-icon" class="refresh-start" src="../img/refresh-icon.svg" height="12" /></button>

once the user clicks the button, refreshContent() will be executed. this function will immediately remove the <img> class attribute titled refresh-end which has a css property of the following; animation-play-state: paused !important. by removing this property, .refresh-start class takes priority with an animation-play-state of running which triggers the animation.

function refreshContent() {

let refreshIcon = document.getElementById("refresh-icon")
let refreshButton = document.getElementById("refresh-button")
refreshButton.removeAttribute("class")
refreshButton.disabled = true

setTimeout(function () {

refreshIcon.addEventListener("animationiteration", function () {
refreshButton.setAttribute("class", "refresh-end")
refreshButton.disabled = false
refreshIcon.removeEventListener("animationiteration")
});

}, 100)

}

stopping the animation

the icon within the button is now rotating but i do want this to stop at some point. ideally i want the button to stop once a task has been completed, and to simulate this i can use setTimeout().

within the setTimeout() function, i need to add an "animationiteration" event listener to the refreshButton element. "animationiteration" is an animation iteration event that occurs when a css animation is repeated. once the animation has repeated, the anonymous function is called which sets the class "refresh-end". as discussed previously, this now pauses the animation. i also remove the disabled attribute from the button to allow the user to click again, if they so wish.