SVG Drawing animation (Part 3) – Loops in LESS

Advanced CSS tutorial: This tutorial covers refining our animation with loops, list & extract in LESS.
Warning: Some maths involved.

Demo

  1. There are a variety of ways to get started with LESS. For this tutorial, I will use a LESS compiler that will compile the LESS and convert into a standard CSS file.
  2. One of the issues we want to solve with LESS is the timings of each pipe in the animation. Some paths of the pipes are longer than others and need to animate faster. LESS will enable me to specify the animation-duration of each pipe without having to write the CSS for every pipe individually.

    I am defining a variable called “times” which I will be referring to later in the code. This behaves like a JavaScript array in which it is storing a list of data. When creating my illustration, I numbered all the pipes in a certain order which applied a ID to each path when it was exported to SVG. My LESS loop will apply these time values to the animation-duration of each pipe e.g. the 6th pipe will have an animation-duration of 2.7s (this will be further explained in step 5).

    @times: 1.7s, .7s, 1.7s, 1.7s, 1.7s, 2.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s;
  3. Now to start the loop. The basic syntax of a loop in LESS starts with: .loop( @parameters ) when ( @condition ) {. The parameter is specifying how many times should it run the loop and the loop will keep going as long as the condition is met. In the code below, I am using a variable @pipe which will be the nth pipe. Number of loops = Number of pipes (15) and the loop will keep going as long there are are pipes to animate.
    @times: 1.7s, .7s, 1.7s, 1.7s, 1.7s, 2.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s;
    .loop(@pipe) when (@pipe > 0) {
    }
    
  4. Now we need to specify what is going to happen during our loop. The first line is selecting the elements affected like normal CSS but I am using the @pipe variable to select the nth pipe e.g. #P1, #P1_extra and the loop will carry on to the next pipe which is #P2, #P2_extra.
    @times: 1.7s, .7s, 1.7s, 1.7s, 1.7s, 2.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s;
    .loop(@pipe) when (@pipe > 0) {
    
        #P@{pipe}, #P@{pipe}_extra {
        }
    }
    
  5. Inside your curly brackets will the CSS applied to every element. Each pipe will have stroke-dasharray: 1000 and stroke-dashoffset: 1000. For the animation, we are going to “extract” the value for the animation-duration from the list in @times. The syntax for this is extract(@[name of list], [index number in the order) so extract(@times, 3) would pick the third value in the @times list. I am using extract(@times, @pipe) to loop through the times in accordance with the nth pipe currently in the loop.

    I have used some maths to work out the animation delay for each pipe. (@pipe*0.15s) means that I want my pipes to start animating every 0.15 seconds, e.g. the fifth pipes will start animating after 0.75 seconds and the sixth pipes will at 0.9 seconds. Once the LESS has generated the CSS, one of pipes will have dash 1.7s forwards linear 2.25s; as the output.

    @times: 1.7s, .7s, 1.7s, 1.7s, 1.7s, 2.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s;
    .loop(@pipe) when (@pipe > 0) {
    
        #P@{pipe}, #P@{pipe}_extra {
            stroke-dasharray: 1000;
            stroke-dashoffset: 1000;
            -webkit-animation: dash extract(@times, @pipe) forwards linear (@pipe*0.15s);
            animation: dash extract(@times, @pipe) forwards linear (@pipe*0.15s);
        }
    
  6. Nested inside the loop, I am adding a function that will be specifying whether the loop is incrementing and decrementing the loop’s parameters.
    For example: .loop( @parameters + 1 ) or .loop( @parameters – 1 )

    @times: 1.7s, .7s, 1.7s, 1.7s, 1.7s, 2.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s;
    .loop(@pipe) when (@pipe > 0) {
    
        #P@{pipe}, #P@{pipe}_extra {
            stroke-dasharray: 1000;
            stroke-dashoffset: 1000;
            -webkit-animation: dash extract(@times, @pipe) forwards linear (@pipe*0.15s);
            animation: dash extract(@times, @pipe) forwards linear (@pipe*0.15s);
        }
    
         // next iteration
         .loop(@pipe - 1);
    }
    
  7. @times: 1.7s, .7s, 1.7s, 1.7s, 1.7s, 2.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s;
    .loop(@pipe) when (@pipe > 0) {
    
        #P@{pipe}, #P@{pipe}_extra {
            stroke-dasharray: 1000;
            stroke-dashoffset: 1000;
            -webkit-animation: dash extract(@times, @pipe) forwards linear (@pipe*0.15s);
            animation: dash extract(@times, @pipe) forwards linear (@pipe*0.15s);
        }
    
         // next iteration
         .loop(@pipe - 1);
    }
    
    // end the loop when index is 0
    .loop(0) {}
    
    #Pipes {
        @p: 15; //num of elements
        .loop(@p);
    }
    
  8. Now we have defined our loop, it is time to run the loop. I am going to apply my loop to #Pipes which is the ID of the SVG on my web page. I am defining a variable of @p which is the number of pipes in my SVG and my .loop (defined on line 2 of the LESS file) will run 15 times.
    @times: 1.7s, .7s, 1.7s, 1.7s, 1.7s, 2.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s, 1.7s;
    .loop(@pipe) when (@pipe > 0) {
    
        #P@{pipe}, #P@{pipe}_extra {
            stroke-dasharray: 1000;
            stroke-dashoffset: 1000;
            -webkit-animation: dash extract(@times, @pipe) forwards linear (@pipe*0.15s);
            animation: dash extract(@times, @pipe) forwards linear (@pipe*0.15s);
        }
    
         // next iteration
         .loop(@pipe - 1);
    }
    
    #Pipes {
        @p: 15; //num of elements
        .loop(@p);
    }
    

That’s the tutorial series finished! You can see the demo of this result here. This tutorial may be too advanced for some visitors but I would greatly appreciate any feedback.

Share
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Leave a Reply

Your email address will not be published. Required fields are marked *