Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Циклы SASS: Программирование

Краеугольной темой препроцессора SASS являются циклы. Они позволяют многократно исполнять какие-либо последовательности действий. В SASS циклы зачастую позволяют генерировать множество классов, которые, впоследствии, можно использовать в проекте.

Перед тем, как перейти непосредственно к написанию и пониманию циклов, введём основной пример, на котором мы и будем изучать все возможные типы циклов в препроцессоре SASS. Представим, что у нас есть список, внутри которого находится 5 элементов: cat, dog, whale, bird, fish. Для каждого из элемента списка нужно составить класс следующего вида:

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

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

Какими путями мы сейчас можем пойти? Первым, что приходит в голову, является использование миксинов. Это действительно хороший вариант, который полностью удовлетворяет нашим запросам:

$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");
  }
}

Теперь, для генерации иконок нам надо выполнить данный миксин для каждого элемента списка. То есть пять раз:

@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));

Иконки готовы — вы великолепны! Можно откинуться на спинку стула и отдохнуть. Это приемлемый вариант, если иконок у нас пять. А что, если в проекте у нас 20 иконок? Или даже 100? Может вы создаёте свою библиотеку с иконками. В таком случае использование метода, который представлен выше — не лучший путь. Он даст нужный результат, но количество строк, которые нужно будет скопировать, достаточно велико. Каким же образом можно облегчить себе жизнь? Для этого в SASS существуют циклы. И с одним из них мы познакомимся прямо сейчас!

Цикл for

Цикл for позволяет задать нам необходимое количество повторений. Это очень удобно, если мы изначально знаем, или можем вычислить необходимое количество повторений блока кода.

Для записи такого цикла используется конструкция @for, у которой необходимо указать счётчик. Счётчик — простой механизм, в котором задаётся начальное и конечное значение. Каждый раз, исполнив блок кода, цикл вначале увеличивает счётчик на единицу, а потом проверяет, не вышло ли значение за границу. Если нет, то выполняем блок кода ещё раз.

Счётчик в цикле for может быть записан одним из двух видов. Примеры ниже сделаны для счётчика от 1 до 5:

  • from 1 to 5. Счётчик с ключевым словом to считается до конечного числа, не включая само конечное число. В данном варианте блок кода исполнится 4 раза.
  • from 1 through 5. Счётчик с ключевым словом through считается до конечного числа, включая конечное число. Цикл с таким счётчиком исполнит блок кода 5 раз.

Все значения счётчика записываются в переменную, имя которой вы указываете сразу после ключевого слова @for. Полная запись цикла выглядит следующим образом:

@for $i from 1 to 5 {
  // Блок кода, который будет исполнен 4 раза.
}

Переменной, объявленной в качестве счётчика, можно пользоваться внутри цикла. В этом легко убедиться на следующем примере:

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

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

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

Счётчик $i был использован для того, чтобы высчитать необходимую сторону квадрата. В результате компиляции получится следующий CSS код:

.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;
}

Обратите внимание, что мы использовали to в условии счётчика, поэтому сгенерировалось 4 класса.

Теперь решение первоначальной задачи становится немного проще. Можно воспользоваться циклом @for и сгенерировать классы столько раз, сколько нам это необходимо.

$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));
}

Думаю после такого кода вы снова великолепны и заслужили откинуться на спинку стула. Возможно вы можете заметить небольшую проблему этого кода — нам необходимо чётко знать количество элементов в списке. И пока это число небольшое, то снова всё отлично. Но как только этих элементов станет к примеру 78, то каждый раз пересчитывать их количество вручную, чтобы внести изменение в счётчик, не доставит вам большого удовольствия.

Может быть есть способ отдать подсчёт самому SASS? Конечно есть — можно воспользоваться функцией length и получить количество элементов в списке. В таком случае наш код может выглядеть следующим образом:

$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));
}

Цикл each

Вторым способом решения задачи по генерации классов с иконками является цикл @each. Этот цикл перебирает значения списка или ассоциативного массива и для каждого значения выполняет блок кода. При использовании данного цикла нам не нужно знать размер списка и создавать счётчики. Мы работаем непосредственно с каждым значением.

Цикл each идеально подходит именно для задачи генерации классов на основе какого-либо списка или ассоциативного массива. Для того, чтобы им воспользоваться, нужно использовать ключевое слово @each, после которого указывается переменная, в которой будет храниться текущее значение из списка. После этого указывается список, из которого эти значения берутся.

$list: 1, 2, 3;

@each $number in $list {
  // блок кода
}

Данный цикл можно прочитать следующим образом: Для каждого числа в списке выполнить и далее блок кода. Прекрасный способ обхода списка, при котором нам не нужно заводить отдельные переменные или обращаться к списку с помощью nth, как было сделано в варианте с циклом @for.

Перенесём нашу задачу по генерации иконок, заменив цикл for на цикл each.

$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);
}

Вот теперь по-настоящему хорошо. Мы использовали именно тот цикл, который нам был нужен и тем самым сократили количество строк и повысили читаемость.

Совет: всегда обращайте внимание на то, какую операцию вы делаете. Если вам нужно просто выполнить блок кода определённое количество раз, то используйте цикл for. При работе со списками/массивами и при использовании их значений используйте цикл each. В большинстве случаев такое разделение поможет сделать ваш код чище.

В примере выше мы рассмотрели, как с помощью @each обойти списки, но с ассоциативными массивами всё немного иначе. Как вы помните, в отличие от списков, где просто происходит перечисление значений, ассоциативные массивы имеют пары ключ-значение. Цикл @each позволяет получать внутри блока кода и ключ, и значение. Для этого необходимо указать через запятую переменную для ключа и переменную для значения. В остальном принцип работы остаётся тем же.

В качестве примера возьмём более сложную структуру списка наших иконок и помимо названия в качестве ключа, они будут содержать так же и размер иконок в виде списка, которые есть в нашем проекте. В данном варианте мы объединим ассоциативный массив и список.

$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;
    width: $icon-size;

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

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

После компиляции мы получим следующий CSS код для иконок с изображением кошки:

.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");
}

Остальные классы будут сгенерированы по аналогии.

В этом примере вы можете увидеть, что мы можем вкладывать циклы друг в друга. Причём эти циклы не обязательно должны быть одного типа. Мы можем вложить @each внутри @for и наоборот. В каждом из этих случаев всё будет работать корректно. Главное, что переменные из внешнего цикла так же попадают и во внутренний. Именно поэтому внутри второго цикла @each можно было использовать переменную $icon, которая создаётся в цикле до этого.

Цикл while

Последним видом циклов, который существует в SASS, является цикл while. Из его названия можно сделать вывод, что он работает по принципу пока выполняется условие.

Для цикла while необходимо указать условие. Пока условие выполняется — цикл отрабатывается. В качестве условия выступают такие же конструкции, как и с условными конструкциями @if/@else.

$count: 1;

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

  $count: $count + 1;
}

После компиляции получится следующий CSS код:

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

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

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

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

Цикл while сложен тем, что в нём очень просто забыть поработать с условием и уйти в бесконечный цикл. Если вы забудете указать $count: $count + 1;, то цикл не закончится никогда. Всегда следите за тем, чтобы условие менялось после каждого выполнения блока кода.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Для полного доступа к курсу нужна профессиональная подписка

Профессиональная подписка откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнения
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 120 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Верстальщик
Профессия
Вёрстка с использованием последних стандартов CSS
в любое время 5 месяцев

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»