Mixins in SASS
This article explains mixins in SASS.
We will explain mixins in SASS with practical examples.
YouTube Video
Mixins in SASS
Overview – What is a Mixin?
Mixins are a mechanism that allows you to define commonly used sets of style properties as reusable functions, which you can call wherever needed. They are very useful for keeping your CSS classes and multiple properties DRY (Don't Repeat Yourself).
Example: The simplest mixin
Below is a simple example of a mixin that reuses border-radius and box-shadow together. By calling this mixin, you can apply the same appearance to multiple elements.
1// Simple mixin that applies border-radius and box-shadow
2@mixin card-style {
3 border-radius: 8px;
4 box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
5 background: #fff;
6}
7
8.card {
9 @include card-style;
10 padding: 1rem;
11}- With this mixin, you no longer need to repeat styles directly.
- Calling it only requires one line:
@include card-style;.
Mixins with Arguments (Parameters)
Mixins can accept arguments, just like functions. This allows you to change the appearance with the same logic. Next is an example where color is taken as an argument.
1// Mixin with parameters: accepts a color and optional radius
2@mixin colored-box($bg-color, $radius: 4px) {
3 background-color: $bg-color;
4 border-radius: $radius;
5 padding: 0.75rem;
6}
7
8.box-primary {
9 @include colored-box(#007acc);
10}
11
12.box-custom {
13 @include colored-box(#ffcc00, 12px);
14}- By providing a default value, you can control the behavior when an argument is omitted.
- In this example, the default radius is used and only the background color is overridden.
Cases where variadic arguments (...) are used
When you want to accept multiple values, you can use variadic arguments ($args...). This is useful for generating utility classes or passing fallback lists.
It's helpful when you need to pass multiple font families or multiple shadow values.
1// Mixin that accepts variable arguments and forwards them to box-shadow
2@mixin multi-shadow($shadows...) {
3 box-shadow: $shadows;
4}
5
6.panel {
7 @include multi-shadow(0 2px 4px rgba(0,0,0,0.08), 0 8px 16px rgba(0,0,0,0.06));
8}- On the calling side, you can pass multiple shadows separated by commas.
- This way, you can use the same mixin for both simple and complex shadows.
Mixins with @content — Receiving a Block
With @content, a mixin can receive a block of styles from the caller. This allows the mixin to provide a common wrapper, while the caller specifies the inner details.
1// Mixin that sets up a responsive container and yields to caller via @content
2@mixin responsive-container($max-width: 1200px) {
3 margin-left: auto;
4 margin-right: auto;
5 padding-left: 1rem;
6 padding-right: 1rem;
7 max-width: $max-width;
8
9 @content; // place where caller's styles are inserted
10}
11
12.header {
13 @include responsive-container(1000px) {
14 display: flex;
15 align-items: center;
16 justify-content: space-between;
17 }
18}- On the calling side, you can add a block to
@includeto insert styles inside. - This pattern is useful for layout wrappers such as grids, cards, and forms.
Advanced Mixins Using Conditionals and Loops
Control structures like @if and @for can be used within mixins. You can use these to automate utility generation and group responsive settings.
Below is an example of automatically generating utility class widths.
1@use 'sass:math';
2
3// Mixin that generates width utility classes from a list of fractions
4@mixin generate-widths($fractions) {
5 @each $name, $fraction in $fractions {
6 .w-#{$name} {
7 width: math.percentage($fraction);
8 }
9 }
10}
11
12$widths: (
13 '1-4': 0.25,
14 '1-3': 0.3333,
15 '1-2': 0.5,
16 '3-4': 0.75
17);
18
19@include generate-widths($widths);- By simply passing a map of the fractions you want to generate on the calling side, you can automatically generate the corresponding utility classes all at once.
- Using this approach has the advantage of reducing manual style definitions while maintaining consistency in your design.
Mixins vs Placeholders (%placeholder)
While mixins directly insert a set of properties, placeholders are used with @extend when inheriting styles. Mixins may generate duplicate CSS in some cases, but @extend can produce more compact CSS in certain situations.
By understanding the purposes and differences in the CSS generated by each method, you will be able to choose the most optimal approach.
1// Placeholder example (for comparison)
2%btn-base {
3 display: inline-block;
4 padding: 0.5rem 1rem;
5 border-radius: 4px;
6}
7
8.btn-primary {
9 @extend %btn-base;
10 background: #007acc;
11 color: #fff;
12}
13
14.btn-secondary {
15 @extend %btn-base;
16 background: #e0e0e0;
17}- When you
@extenda placeholder, multiple selectors can be consolidated into a single rule, resulting in more compact CSS. - On the other hand, since mixins insert properties directly where needed, they offer flexibility and help avoid unintentional selector merging.
Common Practical Patterns (Responsive, Vendor Prefixes, etc.)
In practice, it's useful to put common processing like vendor prefixes and responsive features into mixins. Below is an example that combines transform and prefix properties. You can centralize code for browser compatibility, making maintenance easier.
1// Mixin for transform with vendor prefixes
2@mixin transform($value) {
3 -webkit-transform: $value;
4 -ms-transform: $value;
5 transform: $value;
6}
7
8.icon-rotate {
9 @include transform(rotate(45deg));
10}- The usage is simple and you can use it anywhere, such as
@include transform(rotate(10deg));. - Even if prefixes become unnecessary in the future, maintenance becomes easier because updating the mixin will reflect the change throughout your codebase.
Practical Example: Cards and Buttons Combined
Below is an example where the button styles used within the card are unified with a mixin, allowing them to be switched according to the theme color.
This organizes the commonly used 'card + button' pattern using mixins.
1// Simple mixin that applies border-radius and box-shadow
2@mixin card-style {
3 border-radius: 8px;
4 box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
5 background: #fff;
6}
7
8// Mixin for transform with vendor prefixes
9@mixin transform($value) {
10 -webkit-transform: $value;
11 -ms-transform: $value;
12 transform: $value;
13}
14
15// Button mixin with theme and size parameters
16@mixin btn($bg, $color: #fff, $padding: 0.5rem 1rem) {
17 display: inline-block;
18 padding: $padding;
19 background: $bg;
20 color: $color;
21 border-radius: 6px;
22 text-decoration: none;
23 cursor: pointer;
24 @include transform(translateY(0)); // reuse earlier transform mixin
25}
26
27// Card mixin that accepts inner button styling via @content
28@mixin card($gap: 1rem) {
29 @include card-style; // reuse earlier card-style mixin
30 padding: $gap;
31 @content;
32}
33
34.card-feature {
35 @include card {
36 .title { font-size: 1.125rem; margin-bottom: 0.5rem; }
37 .cta {
38 @include btn(#007acc);
39 }
40 }
41}
42
43.card-warning {
44 @include card {
45 .title { font-weight: bold; }
46 .cta {
47 @include btn(#ff6600);
48 }
49 }
50}- By using these mixins, you can write components succinctly.
Pay Attention to Performance and Generated CSS
Since mixins insert properties each time they are called, extensively using @include for the same rule can make your final CSS larger. You can optimize by combining them with placeholders and component design when needed.
Furthermore, the following measures are also effective.
- Styles that are used frequently should be made into classes for reuse.
- Common patterns should be grouped using
@content. - The generation of complex utilities should only be performed at build time.
Tips for Easier Debugging
When utilizing mixins, it is also important to devise methods to improve debugging and maintainability. By using clear variable names and adding comments within mixins, it will be easier to understand when reviewing the code later. Also, if the functionality becomes complex, dividing the mixin into smaller units will make testing easier and improve maintainability.
Additionally, enabling source maps allows you to easily track which mixin generated which CSS, making it easier to isolate issues.
Below is an example of an easy-to-understand mixin with documentation comments.
1// Example: readable mixin with clear param names and comments
2/// Adds a subtle focus ring for accessibility
3/// $color - ring color
4/// $size - thickness of the ring
5@mixin focus-ring($color: #007acc, $size: 2px) {
6 outline: none;
7 box-shadow: 0 0 0 $size rgba(blue($color), 0.15);
8}- Having organized documentation comments like this makes it easier to share and understand within the team.
- Since SASS documentation comments can be automatically extracted with compatible tools, they are also useful for generating documents such as style guides.
Summary
Since mixins allow you to bundle commonly used styles for reuse, they help reduce code duplication and improve maintainability. Also, when multiple selectors share the same rules, consider using not only mixins but also @extend (placeholders). Furthermore, while @content enables flexible separation of layout wrappers and contents, overusing @include can lead to bloated generated CSS, so caution is advised. It's important to make full use of arguments, default values, and variadic arguments to design mixins that are generic and easy to extend.
You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.