Register to get access to free programming courses with interactive exercises

Cycles SASS: Programming

The cornerstone of the SASS preprocessor are loops. They allow any sequence of actions to be repeatedly executed. In SASS, loops often allow you to generate many classes, which can then be used in the project.

Before we get down to writing and understanding loops, we will introduce a basic example on which we will study all possible types of loops in the SASS preprocessor. Let's imagine that we have a list with 5 elements inside it: cat, dog, whale, bird, fish. For each element of the list we need to make a class of the following kind:

.icon-cat {
  height: 32px;
  width: 32px;

  background: url("../icon/svg/cat.svg");
}

What paths can we take now? The first thing that comes to mind is the use of mixins. This is a really good option, which fully satisfies our needs:

$icons: "cat", "dog", "whale", "bird", "fish";

@mixin icon-32($icon-name) {
  .icon-#{$icon-name} {
    height: 32px;
    width: 32px;

    background: url("../icon/svg/#{$icon-name}.svg");
  }
}

Now, to generate icons, we need to execute this myxin for each item in the list. That is, five times:

@include icon-32(nth($icons, 1));
@include icon-32(nth($icons, 2));
@include icon-32(nth($icons, 3));
@include icon-32(nth($icons, 4));
@include icon-32(nth($icons, 5));

The icons are done - you're gorgeous! You can sit back and relax. This is acceptable if we have five icons. But what if we have 20 icons in the project? Or even 100? Maybe you're creating your own library of icons. In that case, using the method above is not the best way. It will give you the results you need, but the number of lines you will have to copy is quite high. So, how can we make life easier? Well, we have loops in SASS for that. We'll try one of them right now!

The cycle for

The for loop allows us to set the number of repetitions we need. This is very useful if we initially know, or can calculate, the required number of repetitions of a block of code.

To write such a loop, the @for construction is used, for which you need to specify a counter. The counter is a simple mechanism in which a start value and an end value are specified. Each time you execute a code block, the loop first increments the counter by one and then checks to see if the value has exceeded the limit. If not, we execute the code block again.

The counter in the @for loop can be written of one of two kinds. The examples below are made for a counter from 1 to 5:

  • from 1 to 5. The counter with the to keyword counts to a finite number, not including the finite number. In this variant the code block will be executed 4 times.
  • from 1 through 5. A counter with the through keyword counts up to a finite number, including a finite number. A loop with this counter will execute the code block 5 times.

All counter values are written to a variable whose name you specify immediately after the @for keyword. The complete loop entry is as follows:

@for $i from 1 to 5 {
  // A block of code that will be executed 4 times.
}

A variable declared as a counter can be used inside a loop. It is easy to see this in the following example:

@for $i from 1 to 5 {
  $side: $i * 10;

  .square-#{$side} {
    display: block;

    width: #{$side}px;
    height: #{$side}px
  }
}

The $i counter was used to calculate the required side of the square. The result of the compilation is the following CSS code:

.square-10 {
  display: block;
  width: 10px;
  height: 10px;
}

.square-20 {
  display: block;
  width: 20px;
  height: 20px;
}

.square-30 {
  display: block;
  width: 30px;
  height: 30px;
}

.square-40 {
  display: block;
  width: 40px;
  height: 40px;
}

Note that we used to in the counter condition, so 4 classes were generated.

Now the solution to the original problem becomes a bit easier. We can use the @for loop and generate classes as many times as we need.

$icons: "cat", "dog", "whale", "bird", "fish";

@mixin icon-32($icon-name) {
  .icon-#{$icon-name} {
    height: 32px;
    width: 32px;

    background: url("../icon/svg/#{$icon-name}.svg");
  }
}

@for $i from 1 through 5 {
  @include icon-32(nth($icons, $i));
}

I think after this code you are great again and deserve to sit back. You may have noticed a problem with this code - you need to know the number of items in the list. And as long as this number is small, everything is fine again. But as soon as these items become 78, for example, it is not very pleasant to have to recalculate them manually every time to change the counter.

Maybe there is a way to give counting to SASS itself? Of course there is - you can use the length() function and get the number of elements in the list. In that case, our code could look like this:

$icons: "cat", "dog", "whale", "bird", "fish";
$icons-length: length($icons);

@mixin icon-32($icon-name) {
  .icon-#{$icon-name} {
    height: 32px;
    width: 32px;

    background: url("../icon/svg/#{$icon-name}.svg");
  }
}

@for $i from 1 through $icons-length {
  @include icon-32(nth($icons, $i));
}

Cycle of each

The second way to solve the problem of generating classes with icons is the @each loop. This loop search through the values of a list or an associative array and execute a block of code for each value. With this loop, we don't need to know the size of the list or create counters. We work directly with each value.

The @each loop is ideal for the task of generating classes based on a list or an associative array. In order to use it, you have to use the keyword @each, after which you specify the variable in which the current value from the list will be stored. After that the list from which these values are taken is specified.

$list: 1, 2, 3;

@each $number in $list {
  // code block
}

This loop can be read as follows: For each number in the list, execute and then a block of code. This is a nice way to bypass the list without having to create separate variables or refer to the list with nth() as was done in the @for loop variant.

Let's move our icon generation task by replacing the @for loop with the @each loop.

$icons: "cat", "dog", "whale", "bird", "fish";

@mixin icon-32($icon-name) {
  .icon-#{$icon-name} {
    height: 32px;
    width: 32px;

    background: url("../icon/svg/#{$icon-name}.svg");
  }
}

@each $icon in $icons {
  @include icon-32($icon);
}

Now this is really good. We used exactly the loop we needed, thereby reducing the number of lines and increasing readability.


Tip: Always pay attention to the operation you are doing. If you just need to execute a block of code a certain number of times, use the @for loop. When working with lists/arrays and using their values, use the @each loop. In most cases this separation will help make your code cleaner


In the example above, we saw how to bypass lists with @each, but with associative arrays things are a bit different. As you may remember, unlike lists, which simply enumerate values, associative arrays have key-value pairs. The @each loop allows you to get both key and value inside a code block. To do this, you have to specify a comma-separated variable for the key and a variable for the value. Otherwise, the principle is the same.

As an example, let's take the more complex structure of our list of icons, and in addition to the name as a key, they will also contain the size of the icons in the form of a list that we have in our project. In this variant, we will combine an associative array and a list.

$icons: (
  "cat": (32, 64, 128),
  "dog": (32, 64, 128),
  "whale": (32, 64),
  "bird": (16, 32, 64, 128),
  "fish": (32, 64)
);

@mixin icon($icon-name, $icon-size) {
  .icon-#{$icon-size}-#{$icon-name} {
    height: #{$icon-size}px;
    width: #{$icon-size}px;

    background: url("../icon/svg/#{$icon-size}/#{$icon-name}.svg");
  }
}

@each $icon, $sizes in $icons {
  @each $size in $sizes {
    @include icon($icon, $size);
  }
}

After compiling, we get the following CSS code for the cat icons:

.icon-32-cat {
  height: 32px;
  width: 32px;
  background: url("../icon/svg/32/cat.svg");
}

.icon-64-cat {
  height: 64px;
  width: 64px;
  background: url("../icon/svg/64/cat.svg");
}

.icon-128-cat {
  height: 128px;
  width: 128px;
  background: url("../icon/svg/128/cat.svg");
}

The rest of the classes will be generated similarly.

In this example, you can see that we can nest loops inside each other. These loops don't have to be of the same type. We can put @each inside @for and vice versa. In each of these cases, everything will work correctly. The important thing is that the variables from the outer loop also go into the inner loop. That's why inside the second @each loop we could use the variable $icon, which is created in the loop before it.

Cycle while

The last kind of loop that exists in SASS is the @while loop. From its name, we can conclude that it works according to the principle while a condition is fulfilled.

For the @while loop you must specify a condition. As long as the condition is met, the loop is executed. The same constructions as with the conditional @if/@else constructions are used as a condition.

$count: 1;

@while $count < 5 {
  .font-size-#{$count} {
    font-size: #{$count}em;
  }

  $count: $count + 1;
}

After compiling, you will get the following CSS code:

.font-size-1 {
  font-size: 1em;
}

.font-size-2 {
  font-size: 2em;
}

.font-size-3 {
  font-size: 3em;
}

.font-size-4 {
  font-size: 4em;
}

The @while loop is complicated by the fact that it is very easy to forget to work with a condition and go into an infinite loop. If you forget to specify $count: $count + 1;, the loop will never end. Always make sure that the condition changes after each block of code is executed.


Hexlet Experts

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs
profession
Layout with the latest CSS standards
5 months
from scratch
under development
Start at any time

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.