Mixins, Placeholders, and Code Reuse
Build reusable styling abstractions using mixins, parameters, defaults, content blocks, placeholder selectors, and carefully chosen inheritance patterns.
Creating and Including Mixins
A mixin is a reusable block of Sass declarations or rules. Define one with @mixin and include it with @include.
Mixins are useful for repeated patterns such as focus indicators, layout helpers, responsive rules, and compatibility declarations. They can also emit nested selectors and media queries.
Unlike a function, a mixin primarily produces stylesheet output. A function computes and returns a value that can be used in an expression.
Because a mixin's declarations are generally expanded wherever it is included, including a large mixin in many selectors can duplicate CSS. Reuse should be evaluated against the size and clarity of the generated output.
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin focus-ring($color: #333) {
&:focus-visible {
outline: 3px solid $color;
outline-offset: 3px;
}
}
.modal {
@include flex-center;
}
.button {
@include focus-ring(#5b5bd6);
}flex-center mixin emits three declarations. The focus-ring mixin accepts a color argument and generates a nested focus selector.
A mixin is a good abstraction when multiple components need the same meaningful behavior. It is less useful when it merely hides a single obvious declaration without improving consistency.Which pair of directives defines and invokes a Sass mixin?
Mixin Parameters, Defaults, and Keyword Arguments
Mixins can accept positional parameters, default values, and keyword arguments. Parameters make a reusable pattern configurable without duplicating its implementation.
A parameter with a default value is optional. A caller can override that value by passing a positional or named argument.
Keyword arguments are especially useful when a mixin has several parameters because they make call sites self-documenting. Avoid overly generic mixins with many unrelated parameters; several small mixins are often easier to understand.
@mixin container(
$max-width: 72rem,
$gutter: 1rem
) {
width: min(calc(100% - 2 * #{$gutter}), #{$max-width});
margin-inline: auto;
}
.page-container {
@include container;
}
.article-container {
@include container($max-width: 48rem, $gutter: 1.5rem);
}min() and calc() functions perform browser-side layout calculations. Sass interpolation is used to place the configured values into the CSS calculation.What is a major advantage of keyword arguments in a mixin with multiple parameters?
Content Blocks and @content
A mixin can expose a content block using @content. The caller supplies additional Sass content inside the @include block, and the mixin inserts that content at the designated position.
This pattern is useful for reusable media-query wrappers, feature-specific style contexts, and APIs that need to wrap caller-provided declarations.
Content blocks should remain straightforward. Complex nested content APIs can make it difficult to determine where declarations will be emitted.
@mixin respond-to($min-width) {
@media (min-width: $min-width) {
@content;
}
}
.dashboard {
display: grid;
grid-template-columns: 1fr;
@include respond-to(48rem) {
grid-template-columns: 16rem 1fr;
gap: 1.5rem;
}
}What does `@content` allow a mixin to do?
Placeholder Selectors and @extend
A placeholder selector begins with % and is not emitted as a standalone selector unless it is extended by another selector. It is useful for sharing a set of declarations among related selectors.
The @extend directive allows a selector to inherit the selector rules associated with another selector. Sass may combine selectors in generated CSS, which can create larger selector groups than expected.
Mixins and placeholders serve different purposes. Mixins copy declarations into each inclusion point, whereas placeholders and @extend participate in selector unification. Neither is universally superior.
Prefer mixins when the caller needs different parameter values or when explicit component output is desirable. Consider placeholders for tightly related selectors that genuinely share a structural rule set. Avoid extending broad selectors across unrelated components.
Declarations expanded at include sitesSupportedSelectors unifiedNot a mixin-style parameter API%message-base {
padding: 1rem;
border-radius: 0.5rem;
}
.success-message {
@extend %message-base;
color: #155724;
background: #d4edda;
}
.error-message {
@extend %message-base;
color: #721c24;
background: #f8d7da;
}@extend, especially when extending selectors with complex relationships. Selector unification can produce output that is less obvious from the SCSS source.What happens to a placeholder selector such as `%message-base` when it is not extended?