In this post, I want to share how I built the Meesho loader using SVG as shown below. I have explained in a way even If you are complete beginner to SVG, you can expect to understand this implementation.
Overview
The intend of developing this loader is to leverage the inbuilt SVG APIs in HTML5 and avoiding gif usage for simple animations.
SVG can be scaled up without quality loss and comparatively very small in size. SVG can also work with CSS very well in order to achieve desirable shapes with animations. Javascript is not mandatorily required for SVG unlike Canvas and WebGL. SVG can be rendered before external script download and parse delay.
Let us look at the code
Step 1 - Set SVG dimensions
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">
</svg>
Above block of code creates and allocates 300 X 300 space for SVG. We can consider this as a drawing board setup. By default SVG consider the unit in pixels. So It is 300px width and 300px height square here.
Step 2 - Draw a line
Here I have used <path/>
over <line/>
element since there is requirement of lines with circular arc.
Have given two instructions to <path>
element to draw a line. Each instruction will work with or without comma separated. Have used comma here for better readability.
M 30, 250
- Move to 30px horizontally from left and 250px vertically from top of SVG block.
L 30 150
- Draw a line from current position to 30px from left, 150px from top. Since the starting and end position of x values are same, It will be a straight line of length 100px (250 - 150)
Step 3 - Draw an arc
A 50 50 0 0 1 130 150
- Draw an arc from current position to 130px from left and 150px from top with the radius of 50px.
Step 4 - Draw a line again to complete the half shape
L 130 250
- Draw a line from end of arc to the position 130 px from left and 250 px from top. This will now show half of the shape that we are trying to draw. All we have to do now is just repeat.
Step 5 - Repeat the steps to complete full shape
We have to draw one more arc and line to complete.
M 130 150
- Move again to 130px, 150px position from where we are going to draw an arc.
A 50 50 0 0 1 230 150
- Draw another arc of same radius to the position of 230px from left and 150px from top.
L 230 250
- Draw a line from current position to the position of 230px from left and 250px from top.
Step 6 - Adding blunt edge
To make the edge blunt, Found stroke-linecap: round
style exactly fits my requirement.
Step 7 - Add another track for animation
For animation, We need another shape in SVG block with dark pink, same size and positions. It would be easy to just copy paste the path and only change the stroke
property (stroke
property helps to fill the path with given color code).
But We have a problem with using move to
instruction more than once in the <path>
element. When we have multiple move to
, it breaks the path and When try animating it, We would see multiple tracks being animated by considering each move to
as origin with in single path
element.
Since We have used Move to twice in current shape, That will cause an issue in animation If We take the same code.
<path
class='track'
d="M 30 250,L 30 150,A 50 50 0 0 1 130 150, L 130 250,M 130 150,A 50 50 0 0 1 230 150,L 230 250"
/>
I thought of overcoming this move to
issue by starting the second curve right from the end of first curve. Which is 130px from left and 250px from top. So instead of Move to , We can draw a line from 130, 250 to 130, 150
and then draw an arc. This will not break the path and animation also will work fine. But this solution has issue with blunt edge. Since we are starting from end of curve one, The middle edge becomes not an edge, So that stroke-linecap: round
does not apply to middle edge as shown below.
I ended up solving this issue by splitting the curves into two. Move to
also split the curve but If I split then, I will have control to animate in a way I wanted.
Step 8 - Animate the path
Now it's time to animate, The requirement of animation here is to fill the colour of path gradually from left to right and undoing it in same direction.
We can divide this animation requirement in to two for better understanding and I will be referring this term instead of mentioning whole animation in every places,
My goal was to only do animation by CSS properties. Since I am building a loader and that needs to be rendered as soon as possible after the HTML and CSS being downloaded and parsed. If Javascript used then I would have make sure it is not externally loaded and parsed also it should not slow down the main thread Since the animation type we are going to implement is infinite,
First part - sliding in filled path from left to right direction and change state hidden to visible
Second part - sliding filled path in same direction but from visible state to hidden.
As much as I have explored, I found stroke-dashoffset
CSS property which fits my requirement. The default value of stroke-dashoffset
is set to 0, based on the origin where We started our path
element.
We can set initial offset value equal to total length of path we have, And that will move the path entirely to the left side because we have increased the offset same as length of path element.And that will hide the element from the view port.
For animation, We can set the final offset value as 0. Which means element which is hidden will slowly come to the view and fully visible at the end.
Also please note that, To animate using stroke-dashoffset
, We have to use stroke-dasharray
which helps to divide path
into dashes. So we need to declare our curve here as single dash and play with the offset alone. Value of dasharray
will be length of the curve for single dash.
animation: slide 2s infinite ease-in;
@keyframes slide {
100%{
stroke-dashoffset: 0;
}
}
We have implemented the first part of implementation here with the help of animation
property and keyframes
in CSS. keyframes
helps to modify stroke-dashoffset
value at any stage of animation duration. And animation
property consists
animation-name: slide
animation-duration: 2s
animation-iteration-count: infinite
animation-timing-function: ease-in
Further tasks are, Second part of animation and both the curves are animating in same time, We need to arrange in a way that it is flowing.
For second part, We can use same logic . To change from hidden state to slide in visible state, We used offset value 1000 to 0. Like the way If we use 0 to -1000 then path can slide out visible to hidden state.
To avoid animating both the curve same time, We can add animation-delay
to right cure just to align the flow so that It will look like single curve which is being animated from left to right.
Step 8 - Browser compatibility
Above code works perfectly fine for all chromium based browsers but Safari will not accept stroke-dashoffset
propery value in negative. Which is always annoying as a developer to change your logic or way of implementation just for one browser is not compatible with it. But It is also mandatory to fix otherwise your solution will not go production. So went looking for alternate way of animating the same.
Before that, Just to add few points on why chrome supports negative offset value and safari does not. As per the W3C specifications, Negative values are not recommended for stroke-dashoffest
to avoid confusion in moving forward and backward direction. But Chrome team might have thought it is not a confusion, but restriction. So they have enabled it. But Safari stick to the specs which is also not questionable.
Coming back to the solutioning, I straight away could not find the alternate solution for second part of animation to replace negative offset.But after playing with offset and dasharray properties a lot, Arrived to this hacky way I should call it because there is no other proper solution I found.
We can achieve second part of animation by animating stroke-dasharray
property from 1000 0
to 0 1000
. Which means from dash width 1000px and gap value 0 to dash width 0 and gap value 1000px. Here since dash value gradually reduces to 0, We can achieve second part of animation.
So the idea here is to combine both the ways. Animating with dashoffset
value for first part and with dasharray
for second part.
Here, As soon as the first part of animation is done, I am resetting the value for second part instantly at 51%. Instant from 50 to 51 to avoid animation between dasharray
value 1000
to 1000 0
.
Also I have increased dashoffset
value by 100px to avoid flickering since we are animating both offset and dasharray
properties.
Conclusion
Now that you know How I have built this loader. Please comment If there is any other way the same is possible. Doesn't matter whether it is better approach or not but curious to know.
Top comments (1)
Great way to explain the process via coding. Since you asked, you can also create this using a no-code animation tool like svgator.com .
Thank you for sharing!