Register to get access to free programming courses with interactive exercises

Mixins as functions SASS: Programming

Perhaps the main feature of mixins is that they can accept arguments that we can use internally. Programmers call such portions of code functions. They make it easier to reuse the code. So how do we use this in SASS? Let's take a simple class mx-10 that indents left and right by 10 pixels:

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

What if we want to add more of these classes? For example, mx-5, mx-10, mx-15, mx-20, and so on. Of course, we can handwrite all the classes we need and set their properties. But this is a boringly long process. Let's first try to put the properties margin-left and margin-right into a mixin so that we don't have to specify them every time:

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

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

It seems that not only did nothing much change, but we also added extra code. How does this help us in removing duplicate code? It is where the peculiarity of mixins to accept arguments comes into play.

Arguments are variables on which the result of a function depends. They are given in parentheses and can have any name. We specify each argument with the $ key symbol. If there is more than one argument, they are listed separately by commas.

Let's add two arguments to our mixin. The first argument will point to the value of the margin-right property, and the second argument to the value of the margin-left property:

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

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

The second step to turn a simple mixin into a function is to substitute arguments for the properties within the mixin.

To do this, we substitute the arguments we need instead of the values of the properties:

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

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

If we try to compile this code now, we get the following error:

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

The preprocessor tells us that the$mr is missing. It means that once we add arguments to the mixin, we can't call without them, even if we don't use them in the mixin.

Let's correct the error and add two arguments when calling the mixin. We specify the arguments in parentheses and put the value we expect. In this case, it is 10px:

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

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

After compiling, we get exactly the code we wanted from the beginning:

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

The difference now is that we can conveniently write new classes without constantly duplicating properties:

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

And in this case, since we have repetitive property values, we can pass just one argument and use it in two properties at once:

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

It is good practice if the properties are related to each other. For example, using the same argument to pass the height and margin-top properties is not a good idea, even if they have the same value. You'll confuse the code and reduce your customization options for the selectors.

The last example showed what happens if you don't specify an argument when you call a mixin. It will not always cause an error because mixins can take arguments by default. If no arguments were specified when calling the mixin, that is what the preprocessor will use.

We specify these arguments directly when we list them and create the mixin. All we have to do is to specify values like a simple variable. It is similar to how the !default' flag was set for a variable:

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

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

Since we didn't specify any arguments when calling the mixin, the compiler will take the default value specified when we created the mixin. After compiling, we'll get the following CSS code:

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

Using the ability of mixins to accept arguments helps a lot when creating property templates with vendor prefixes. In the last lesson, we learned how to make a mixin with the box-shadow property and its vendor prefixes. By using the ability to specify arguments, we can reduce our code when reusing it with other values:

@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 0 rgba(204, 204, 204, 1));
}

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

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

After compiling, we get the following CSS:

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

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

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

Transferring properties in the mixin

In addition to arguments, we can pass the entire CSS code to the mixin. It is useful when, in addition to some values, we need to work with custom CSS, which is absent in the mixin.

You can transfer the content to the mixin as follows:

@include mixin-name($arg1, $arg2) {
  // The content we want to transfer to the mixin
}

You can get this content inside the mixin by using the @content construct, which will take the entire body from the mixin call and add it to where the @content construct as specified:

@mixin btn {
  display: block;
  padding: 20px;

  font-weight: bold;
  font-size: 0.8em;
  color: #333;

  @content;
}

.btn {
  @include btn {
    &.btn-blue {
      background: #42a5f5;
      color: #fff;
    }
  }
}

After compiling, we get the following CSS code:

.btn {
  display: block;
  padding: 20px;
  font-weight: bold;
  font-size: 0.8em;
  color: #333;
}

.btn.btn-blue {
  background: #42a5f5;
  color: #fff;
}

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

The Hexlet support team or other students will answer you.

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:

Bookmate
Health Samurai
Dualboot
ABBYY
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.