Миксины как функции

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

.mx-10 {
  margin-right: 10px;
  margin-left: 10px;
}

Что делать, если мы захотим сделать больше таких классов? Например .mx-5, mx-10, mx-15, mx-20 и так далее. Конечно можно руками прописать все нужные нам классы и задать им свойства. Но это достаточно монотонный и долгий процесс. Попробуем для начала вынести свойства margin-left и margin-right в миксин, чтобы не было необходимости каждый раз их указывать.

@mixin margin-x {
  margin-right: 10px;
  margin-left: 10px;
}

.mx-10 {
  @include margin-x;
}

Кажется, что мало того, что ничего особо не поменялось, так мы ещё и добавили лишний код. Как нам это поможет в выносе дублирующего кода? Тут на сцену и выходит особенность миксинов принимать аргументы. Аргумент — некая переменная, от которой зависит результат выполнения функции. Аргументы указываются в круглых скобках и могут иметь любое имя. Каждый аргумент указывается с ключевым символом $. Если аргументов несколько, то они перечисляются через запятую. Добавим два аргумента в наш миксин. Первый аргумент будет указывать на значение свойства margin-right, а второй аргумент на значение свойства margin-left.

@mixin margin-x($mr, $ml) {
  margin-right: 10px;
  margin-left: 10px;
}

.mx-10 {
  @include margin-x;
}

Вторым шагом по превращению простого миксина в функцию является подстановка аргументов в свойства внутри миксина. Для этого вместо значений свойств подставим нужные нам аргументы.

@mixin margin-x($mr, $ml) {
  margin-right: $mr;
  margin-left: $ml;
}

.mx-10 {
  @include margin-x;
}

Если попробовать сейчас скомпилировать этот код, то получим следующую ошибку:

Error: Missing argument $mr.
  ╷
7 │   @include margin-x;
  │   ^^^^^^^^^^^^^^^^^^^
  ╵

Препроцессор сообщает нам, что отсутствует аргумент $mr. Это значит, что как только мы в миксин добавляем аргументы, то вызов без них невозможен. Даже если сами аргументы не будут использованы в миксине. Поправим ошибку и добавим 2 аргумента при вызове миксина. Аргументы также указываются в круглых скобках и туда мы помещаем то значение, которое ожидаем. В данном случае 10px.

@mixin margin-x($mr, $ml) {
  margin-right: $mr;
  margin-left: $ml;
}

.mx-10 {
  @include margin-x(10px, 10px);
}

После компиляции мы получим именно тот код, который и хотели получить с самого начала:

.mx-10 {
  margin-right: 10px;
  margin-left: 10px;
}

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

@mixin margin-x($mr, $ml) {
  margin-right: $mr;
  margin-left: $ml;
}

.mx-10 {
  @include margin-x(10px, 10px);
}

.mx-15 {
  @include margin-x(15px, 15px);
}

.mx-20 {
  @include margin-x(20px, 20px);
}

.mx-25 {
  @include margin-x(25px, 25px);
}

А в данном случае, так как значения свойств у нас повторяются, то мы можем передавать всего один аргумент и использовать его в двух свойствах сразу.

@mixin margin-x($margin) {
  margin-right: $margin;
  margin-left: $margin;
}

.mx-10 {
  @include margin-x(10px);
}

.mx-15 {
  @include margin-x(15px);
}

.mx-20 {
  @include margin-x(20px);
}

.mx-25 {
  @include margin-x(25px);
}

Это хорошая практика, если свойства «родственны» друг другу. Использовать один аргумент для передачи, например, свойства height и margin-top не очень хорошая идея, даже если они и имеют одно значение. Так вы внесёте путаницу в код и уменьшите собственные возможности по кастомизации селекторов.

В прошлом примере было показано, что случится, если не указать аргумент при вызове миксина. На самом деле это не всегда вызовет ошибку, так как миксины могут принимать аргументы по умолчанию. Если при вызове миксина не было указано никаких аргументов, то препроцессор будет пользоваться именно ими. Эти аргументы указываются непосредственно при создании миксина и указании аргументов. Всё, что нам нужно — указать значения, как у простой переменной. Это схоже с тем, как у переменной устанавливался флаг !default.

@mixin margin-x($margin: 10px) {
  margin-right: $margin;
  margin-left: $margin;
}

.mx-10 {
  @include margin-x();
}

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

.mx-10 {
  margin-right: 10px;
  margin-left: 10px;
}

Использовать возможность миксинов принимать аргументы сильно помогает при создании шаблонов свойств с вендорными префиксами. В прошлом уроке мы посмотрели, как сделать миксин со свойством box-shadow и его вендорными префиксами. Использовав возможность указывать аргументы, мы можем сильно сократить наш код при повторном использовании с другими значениями.

@mixin box-shadow-prefix ($value) {
  -webkit-box-shadow: $value;
  -moz-box-shadow: $value;
  box-shadow: $value;
}

.box-shadow-small {
  @include box-shadow-prefix (3px 3px 3px 0px rgba(204,204,204,1));
}

.box-shadow-medium {
  @include box-shadow-prefix (7px 7px 3px 0px rgba(204,204,204,1));
}

.box-shadow-big {
  @include box-shadow-prefix (10px 10px 3px 0px rgba(204,204,204,1));
}

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

.box-shadow-small {
  -webkit-box-shadow: 3px 3px 3px 0px #cccccc;
  -moz-box-shadow: 3px 3px 3px 0px #cccccc;
  box-shadow: 3px 3px 3px 0px #cccccc;
}

.box-shadow-medium {
  -webkit-box-shadow: 7px 7px 3px 0px #cccccc;
  -moz-box-shadow: 7px 7px 3px 0px #cccccc;
  box-shadow: 7px 7px 3px 0px #cccccc;
}

.box-shadow-big {
  -webkit-box-shadow: 10px 10px 3px 0px #cccccc;
  -moz-box-shadow: 10px 10px 3px 0px #cccccc;
  box-shadow: 10px 10px 3px 0px #cccccc;
}
Мы учим программированию с нуля до стажировки и работы. Попробуйте наш бесплатный курс «Введение в программирование» или полные программы обучения по Javascript, PHP, Python и Java.

Хекслет

Подробнее о том, почему наше обучение работает →