Sass: Mixin or Placeholder?

Share this article

When I started playing with Sass about a year and a half ago, one thing that took me some time to understand was the difference between including a mixin and extending a placeholder. Actually even the notion of placeholder was kind of black magic voodoo for me back then.

If you are in a similar situation, don’t worry, because I will try to enlighten the path. Today we’ll learn what exactly a mixin is for, and when to use a Sass placeholder. You’ll understand they both serve different purposes and shouldn’t be confused.

Note: While I am going to talk about Sass, this article could well apply to any other CSS preprocessor, whether it be Stylus, LESS, or whatever you happen to use. The technologies are generally doing the same thing, so feel free to adapt the content of this article to the tool of your choice.

First we should probably do some catch up on what we are talking about when we refer to Sass placeholders and mixins, so let’s do that now.

Mixin it Up

A mixin is a directive that allows you to define multiple rules depending on several arguments. Think of it as a function that would dump CSS content instead of returning a value. Here is the definition from the Sass Reference:

Mixins allow you to define styles that can be re-used throughout the stylesheet without needing to resort to non-semantic classes like .float-left. Mixins can also contain full CSS rules, and anything else allowed elsewhere in a Sass document. They can even take arguments which allows you to produce a wide variety of styles with very few mixins.

Now that we’ve covered terminology, let’s say you spot a couple of declarations that are repeated multiple times across your stylesheet. You know that code repetition is bad and you are familiar with the DRY (Don’t Repeat Yourself) concept. To correct this, you can write a mixin for those repeated declarations:

@mixin center() {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.container {
  @include center();
  /* Other styles here... */
}

/* Other styles... */

.image-cover {
  @include center;
}

Note: If you don’t pass an argument to a mixin, you can omit the parentheses. In fact, you can even omit them in the @mixin definition.

With this newly created mixin way you don’t have to repeat those three lines every time you need to center an element; you simply include the mixin. Pretty convenient, isn’t it!

Sometimes you want a mixin to build what you would call a “shorthand” for a couple of properties. For example, width and height. Aren’t you tired of writing both lines over and over again? Especially when both have the same value? Well let’s deal with that using a mixin!

@mixin size($width, $height: $width) {
  width: $width;
  height: $height;
}

Quite simple, isn’t it? Note how we made the $height parameter optional by defaulting it to have the same value as the $width directly in the mixin signature. Now whenever you need to define dimensions for an element, you can just do this:

.icon {
  @include size(32px);
}

.cover {
  @include size(100%, 10em);
}

Note: another good example of a syntactic-sugar mixin would be this one I made to avoid writing top, right, bottom, left and position every time I want to use a different position system than static.

Know Your Placeholder

Placeholders are kind of a weird thing. They are classes that aren’t output when your SCSS is compiled. So then you might think “What’s the point?”. Actually the point would be minimal if it wasn’t for the @extend directive. But first things first. This is how you write a placeholder:

%center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

Editors Note: Like a placholder, a mixin is likewise useless unless its referenced, so this section is not necessarily saying they are different in that respect, but this is only clarifying that even though it looks similar to a CSS declaration block, it won’t get compiled on its own.

Basically you write it exactly like a class except you prefix it with the % symbol instead of a dot. Also, it follows the same naming rules as classes.

Now if you try to compile your SCSS, you won’t see this sample of code in the generated file. As I’ve said: placeholders are not compiled to the source.

So for now, this placeholder is absolutely useless. You can’t make any use of it unless you look at the @extend side. The @extend directive aims to inherit properties from a CSS selector / SCSS placeholder. Here is how you use it:

.container {
  @extend %center;
}

By doing this, Sass will get the content of the %center placeholder and apply it to .container (even if that’s actually not quite how it’s done — but that doesn’t matter right now). As I said, you can also extend existing CSS selectors (in addition to SCSS placeholders) like this:

.table-zebra {
  @extend .table;

  tr:nth-of-type(even) {
    background: rgba(0,0,0,.5);
  }
}

This is a very common use case for the @extend directive. In this case, we ask for the .table-zebra class to behave exactly like the .table class and then we add the zebra-specific rules. Extending selectors is very convenient when you develop your site/application in modular components.

Which One to Use?

So the question remains: which one should you use? Well, as for everything in our field: it depends. It depends on the context and what you are ultimately trying to do.

The best advice would be: if you need variables, use a mixin. Otherwise, extend a placeholder. There are two reasons for this:

  • First, you can’t use variables in a placeholder. Actually you can but you cannot pass variables to your placeholders so you can’t generate context-specific CSS like you would do with a mixin.
  • Second, the way Sass handles mixins makes them very inconvenient when you don’t use them with contextual variables. To put it simply: Sass will duplicate the output of the mixin every time you use it, resulting not only in duplicated CSS but also a bigger stylesheet.

Consider the very first example in this article:

@mixin center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.container {
  @include center;
}

.image-cover {
  @include center;
}

This will result in the following CSS output:

.container {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.image-cover {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

Notice the duplicate CSS? It won’t do much harm if it’s only three lines duplicated, but if you have mixins dumping dozens of CSS lines and used multiple times across a project, those three lines could easily become 300. What if we revamp our example to instead use a placeholder?

%center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.container {
  @extend %center;
}

.image-cover {
  @extend %center;
}

Now this is the generated CSS:

.container, .image-cover {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

Much better! The compilation takes advantage of selector grouping without any repeated styles. So whenever you want to avoid writing the same properties over and over, knowing that they won’t ever change, it is a good idea to extend a placeholder. This will result in a much leaner compiled stylesheet.

On the other hand if you are willing to write the same properties at various places but with different values (sizes, colors, etc.) a mixin is the best way to go. If you have a group of both fixed values and variables values, you should try a combination of both.

%center {
  margin-left: auto;
  margin-right: auto;
  display: block;
}

@mixin skin($color, $size) {
  @extend %center;
  background: $color;
  height: $size;
}

a { @include skin(pink, 10em) }
b { @include skin(blue, 90px) }

In this case, the mixin is extending the placeholder for fixed values instead of dumping them directly in its body. This generates clean CSS:

a, b {
  margin-left: auto;
  margin-right: auto;
  display: block;
}

a {
  background: pink;
  height: 10em;
}

b {
  background: blue;
  height: 90px;
}

Conclusion

So there you have it. I hope I’ve made it clear not only what mixins and placeholders are for, but also when you should use them and what effect they will have on the compiled CSS.

If you have anything to add regarding your experiences with these features in CSS preprocessors, feel free to share them in the comments.

This article was translated into French by Pierre Choffé on La Cascade

Frequently Asked Questions (FAQs) about Sass Mixin and Placeholder

What is the main difference between Sass Mixin and Placeholder?

The primary difference between Sass Mixin and Placeholder lies in their usage. Mixins are reusable styles that can be included in other Sass rules. They can accept arguments, which makes them highly flexible and customizable. On the other hand, placeholders are a type of selector that allows you to define styles that can be extended but not directly output in your compiled CSS. This means that the styles defined in a placeholder will only appear in your CSS if they are extended by another selector.

Can you provide an example of how to use a Sass Placeholder?

Sure, here’s a simple example of how to use a Sass placeholder:

%my-placeholder {
color: blue;
font-size: 20px;
}

.my-class {
@extend %my-placeholder;
}

In this example, the styles defined in %my-placeholder will be applied to .my-class in the compiled CSS.

How can I pass arguments to a Sass Mixin?

Passing arguments to a Sass Mixin is straightforward. Here’s an example:

@mixin my-mixin($color, $font-size) {
color: $color;
font-size: $font-size;
}

.my-class {
@include my-mixin(blue, 20px);
}

In this example, the my-mixin mixin accepts two arguments: $color and $font-size. These arguments are then used within the mixin to set the color and font-size properties.

Can I use both Mixins and Placeholders in the same project?

Absolutely! Mixins and placeholders can be used together in the same project. They each have their own strengths and can complement each other well. For example, you might use a mixin to define a complex set of styles that need to be reused with different values, and a placeholder to define a set of base styles that are extended by multiple selectors.

Are there any performance considerations when using Mixins and Placeholders?

Yes, there can be performance considerations when using mixins and placeholders. Mixins can lead to duplicated CSS if they are included in multiple places with the same arguments. On the other hand, placeholders can help to reduce duplication by only outputting the styles where they are extended. However, overuse of placeholders can also lead to bloated CSS if many selectors extend the same placeholder.

Can I use default values in Sass Mixins?

Yes, you can specify default values for arguments in Sass mixins. If an argument is not passed when the mixin is included, the default value will be used. Here’s an example:

@mixin my-mixin($color: blue, $font-size: 20px) {
color: $color;
font-size: $font-size;
}

.my-class {
@include my-mixin;
}

In this example, if no arguments are passed to my-mixin, it will use blue for $color and 20px for $font-size.

How can I use Mixins and Placeholders to improve code maintainability?

Mixins and placeholders can greatly improve code maintainability by promoting reusability and DRY (Don’t Repeat Yourself) principles. By defining common styles in mixins and placeholders, you can avoid repeating the same styles in multiple places. This makes your code easier to maintain and update, as changes only need to be made in one place.

Can I nest Mixins and Placeholders?

Yes, you can nest mixins and placeholders within other rules or within each other. This can be useful for creating complex styles or for organizing your code. However, be careful not to overuse nesting as it can make your code harder to read and maintain.

Can I use Mixins and Placeholders with other Sass features?

Yes, mixins and placeholders can be used with other Sass features such as variables, functions, and control directives. This allows you to create highly flexible and powerful styles.

Are there any best practices for using Mixins and Placeholders?

Some best practices for using mixins and placeholders include: use mixins for styles that need to be reused with different values; use placeholders for styles that are extended by multiple selectors; avoid overusing mixins as they can lead to duplicated CSS; use default values in mixins where appropriate; and use nesting judiciously to keep your code readable and maintainable.

Kitty GiraudelKitty Giraudel
View Author

Non-binary trans accessibility & diversity advocate, frontend developer, author. Real life cat. She/they.

AdvancedCSSCSS Preprocessingsass
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week