Generating Reusable CSS Blocks with SCSS Mixins

Mixins are powerful SCSS tools that generate customisable CSS blocks, unlike functions or inheritance. They accommodate parameters, defaults, and conditional logic to streamline coding. Used correctly, they enhance reusability while minimising complexity in stylesheets.

Earlier in this series we looked at functions, which compute and return a single value, and inheritance, which shares a fixed set of styles between selectors. Mixins sit alongside both and fill the gap neither covers: they generate whole blocks of CSS, and they can take parameters to customise what they produce. When you find yourself writing the same group of declarations repeatedly, especially declarations that need to vary slightly each time, a mixin is usually the right tool.

What a Mixin Is

A mixin is a named block of CSS rules that you define once and drop into any selector that needs it. Unlike a function, which hands back a single value, a mixin outputs full property declarations. Unlike inheritance, which merges selectors into a shared rule, a mixin includes its styles directly into each selector that uses it, and it can accept arguments to change what those styles are.

That last point is the real reason to reach for a mixin. When the shared styles are identical every time, inheritance often does the job. When they need to differ based on input, a mixin is what you want.

Defining and Including a Mixin

A mixin is defined with the @mixin directive, given a name, and optionally a list of parameters. You then drop it into a selector with @include:

@mixin rounded-corners($radius) {
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
border-radius: $radius;
}
.cta-button {
background-color: #3498db;
color: #fff;
padding: 10px 20px;
@include rounded-corners(5px);
}

The @include rounded-corners(5px) line pulls all three border-radius declarations into .cta-button with the radius set to 5px. The vendor prefixes are written once in the mixin rather than repeated in every selector that needs rounded corners, which is exactly the kind of tedious repetition mixins exist to remove.

Giving Parameters Default Values

Parameters can carry default values, which makes them optional. If the caller does not supply a value, the default is used:

@mixin drop-shadow($x: 0, $y: 3px, $blur: 4px, $color: rgba(0, 0, 0, 0.3)) {
-webkit-box-shadow: $x $y $blur $color;
-moz-box-shadow: $x $y $blur $color;
box-shadow: $x $y $blur $color;
}
.panel {
background: #fff;
padding: 20px;
@include drop-shadow();
}

Here .panel calls the mixin with no arguments at all, so it gets the default shadow. Another selector could override just the values it cares about while leaving the rest at their defaults. This is what makes a mixin flexible: sensible defaults for the common case, with the option to customise when needed.

Generating Responsive Styles

Because a mixin outputs whole blocks rather than single values, it can include things like media queries. This makes it well suited to responsive patterns that would otherwise be repeated across many selectors:

@mixin fluid-type($size-small, $size-large) {
font-size: $size-small;
@media (min-width: 768px) {
font-size: $size-large;
}
}
h1 {
@include fluid-type(1.5rem, 2.5rem);
}

The heading gets a smaller font size on narrow viewports and a larger one once the screen reaches 768 pixels wide. The breakpoint logic lives in one place. If you decide to change the breakpoint later, you change the mixin and every heading using it updates at once.

Adding Conditional Logic

Mixins can also branch internally, producing different output depending on the arguments they receive:

@mixin tinted-background($color, $dark: false) {
@if $dark {
background-color: darken($color, 20%);
} @else {
background-color: lighten($color, 20%);
}
}
.notice {
@include tinted-background(#e74c3c, $dark: true);
}

The @if and @else inside the mixin decide whether to darken or lighten the colour based on the $dark flag. Passing $dark: trueby name makes the intent obvious at the call site. This kind of conditional logic lets a single mixin handle several related cases without forcing you to write a separate mixin for each one.

Keeping Mixins Useful

Keep each mixin focused on one job. A mixin for rounded corners, a mixin for shadows, a mixin for responsive type. When a mixin tries to handle several unrelated concerns at once, it becomes hard to reuse and harder to debug.

Name mixins after what they produce. rounded-corners, fluid-type, and tinted-background tell you what you are getting. Vague names force the reader to open the mixin to find out what it does.

Resist the urge to build elaborate mixins with many parameters and deep conditional logic. The point of a mixin is to simplify, and a mixin complex enough to need its own documentation often signals that the problem should be broken into smaller pieces.

Store your mixins in a dedicated partial, conventionally named _mixins.scss, and import it into your main stylesheet. Keeping them in one place makes them easy to find and reuse across the whole project rather than scattered through individual component files.

Comment your parameters when their purpose is not self-evident. For a mixin with several arguments or conditional behaviour, a short note explaining what each parameter controls saves the next person, possibly you, from tracing through the logic to work it out.

The Takeaway

Mixins are the most flexible of the three SCSS reuse tools. Functions return values, inheritance shares fixed styles, and mixins generate customisable blocks of CSS. The ability to take parameters, fall back on defaults, include media queries, and branch on conditions makes them the natural choice whenever the styles you want to reuse need to vary from one use to the next. Used with focus and clear names, they cut repetition without adding the kind of complexity that makes a stylesheet harder to reason about.

See you soon

View Comments (9)

Leave a Reply

Subscribe to My Newsletter

Subscribe to my email newsletter to get the latest posts delivered right to your email. Pure inspiration, zero spam.

Discover more from Discuss Data Science, Machine Learning and Analytics

Subscribe now to keep reading and get access to the full archive.

Continue reading