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.