Sass Mixins: What are They?

In recent years HTML has made great strides towards becoming more semantic. Tags like <aside> and <article> enforce the meaning of the content rather than its layout. Unfortunately, the same isn’t true of CSS. Defining classes like .float-left, .row, and .col is better than re-defining float properties for every HTML tag, but they hardly add to the meaning of the HTML.

There are CSS frameworks around they try to address the problem. (Semantic UI is a popular example; you’ll find it at semantic-ui.com.) Sass provides another way, via the @mixin directive. Mixins are primarily used to provide non-semantic styling, but they can contain any valid CSS or Sass. The syntax is straight-forward:

Syntax:

@mixin <name>
{
<contents>
}

Once you’ve created the mixin, simply use @include where you want the rules to be included in your file.

Syntax:

<selector>
{
@include <mixin-name>
[<other rules>]}

Let’s look at a simple example.

SCSS: Mixin

@mixin float-left {
float: left;
}
.call-out {
@include float-left;
background-color: gray;
}

The resulting CSS will be:

.call-out {
float: left;
background-color: gray;
}

The mixin in the above example is defined in the same file where it’s used, but you can (and usually will) define mixins in a partial. Just @import the file itself before you use the @include directive.

A Sass mixin isn’t restricted to just defining property rules; it can also include selectors, including parent selectors. Using this technique, you could, for example, define all the rules for a button-like link in a single mixin:

SCSS:

@mixin a-button {
a {
background-color: blue;
color: white;
radius: 3px;
margin: 2px;

&:hover {
color: red;
}
&:visited {
color: green;
}
}
}

Use the @include directive to include this mixin in a style, as shown below:

SCSS: @include Mixin

@include a-button.scss //assuming a-button.scss is the name of above mixin file.menu-button {
@include a-button;
}

and the output would be:

CSS:

.menu-button a {
background-color: blue;
color: white;
radius: 3px;
margin: 2px;
}
.menu-button a:hover {
color: red;
}
.menu-button a:visited {
color: green;
}

Mixin Variables

If you have more than one class that includes this functionality, it’s clear that the previous example will save a lot of typing and be more maintainable. But what if you have several classes that have the same basic functionality, but you need to pass different colors? Sass makes it easy: just pass the colors as variables, which are defined like function parameters:

SCSS: Mixin Variable

@mixin a-button($base, $hover, $link) {
a {
background-color: $base;
color: white;
radius: 3px;
margin: 2px;

&:hover {
color: $hover;
}
&:visited {
color: $link;
}
}
}

You pass the variable arguments to the mixin using the normal syntax:

SCSS:

.menu-button {
@include a-button(blue, red, green);
}
.text-button {
@include a-button(yellow, black, grey);
}

That example would result in the following CSS:

.menu-button a {
background-color: blue;
color: white;
radius: 3px;
margin: 2px;
}
.menu-button a:hover {
color: red;
}
.menu-button a:visited {
color: green;
}
.text-button a {
background-color: yellow;
color: white;
radius: 3px;
margin: 2px;
}
.text-button a:hover {
color: black;
}
.text-button a:visited {
color: grey;
}

Sass even lets you provide default values for mixin variables:

SCSS:

@mixin a-button($base: red, $hover: green, $link: blue) {
a {
background-color: $base;
color: white;
radius: 3px;
margin: 2px;
&:hover {
color: $hover;
}
&:visited {
color: $link;
}
}
}

When you define a default variable in this way, you only need to provide values that change when you include the mixin:

SCSS:

.menu-button {
@include a-button($link: orange);
}

This would result in the following CSS:

.menu-button a {
background-color: blue;
color: white;
radius: 3px;
margin: 2px;
}
.menu-button a:hover {
color: red;
}
.menu-button a:visited {
color: orange;
}

As you can see, the a:visited rule is assigned color: orange, as provided, but the other two rules have the default values.

Just as when you call a Sass function, you only need to provide the parameter name if you’re not including the arguments out of order or skipping some. This would work just fine (although the resulting button would be pretty ugly):

SCSS:

.menu-button {
@include a-button(darkmagenta, darkolivegreen, skyblue);
}

Variable Variables

Some CSS properties can take different numbers of variables. An example is the margin property, which can take from 1 to 4 values. Sass supports these using variable arguments, which are declared with an ellipsis after their names:

SCSS: Mixin Variables

@mixin margin-mix($margin...) {
margin: $margin;
}

Given this mixin definition, any of the following @include directives will transpile without error:

SCSS:

.narrow-border {
@include margin-mix(1px);
}
.top-bottom-border {
@include margin-mix(3px 2px);
}
.varied-border {
@include margin-mix(1px 3px 6px 10px);
}

and with the expected results:

CSS:

.narrow-border {
margin: 1px;
}
.top-bottom-border {
margin: 3px 2px;
}
.varied-border {
margin: 1px 3px 6px 10px;
}

Passing Content to Mixins

Most often you’ll use mixins for standard bits of styling that you’ll use in multiple places and expand with additional rules when you include them. But you can build mixins that work the other way by passing a block of rules to the mixin. You don’t need a variable to do this; the content you pass will be available to the mixin via the @content directive:

SCSS:

@mixin has-content {
html {
@content;
}
}
@include has-content {
#logo {
background-image: url(logo.svg);
}
}

This will result in the following CSS output:

html #logo {
background-image: url(logo.svg);
}

Notice the syntax here uses braces, not parentheses, to distinguish the content from any variables the mixin might declare. You can use both;

SCSS:

@mixin test-content($color) {
.test {
color: $color;
@content;
}
}
@include test-content(blue) {
background-color: red;
}

which will result in the following CSS:

.test {
color: blue;
background-color: red;
}

Passing content into a mixin isn’t something you’ll need to do very often, but it can be useful, particularly when you’re dealing with media queries or browser-specific property names. Hope you found this helpful. Feel free to reach to me on LinkedIn. Happy Coding!

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

IoT and LPWAN Protocols

Top Visual Studio Code Extensions for Web Development

Java Character Streams: BufferedReader, InputStreamReader etc.

How Angular Protects Us From XSS Attacks?

Incorrect use of ParentData Widget. Expanded widget Must be Placed Inside the flex widget.

Matrix Labs Monthly Update (March 2022)

Solutions to the testing challenges when working agile at scale

You’re Either Getting Better or You’re Getting Worse

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Marcus Siegel

Marcus Siegel

More from Medium

How to Use UniLend Finance to Long or Short Any Asset

The loss of Civility

Keeping Your Kidneys Healthy — Season

December 27, 2021