Using Stylus Mixins with @content to Reduce CSS Duplication
Learn how Stylus mixins with @content let you share common styles while injecting unique declarations, cutting CSS duplication and keeping your stylesheet maintainable.
07 Jun 2026, 15:15 UTC

The problem: repeating similar rule sets
When building a UI component library, you often find yourself writing almost identical rule sets for variations of the same element—for example, buttons that share padding, font size, and border radius but differ in background color and hover state. Copy‑pasting these blocks leads to maintenance overhead: a change to the shared style must be repeated in every variant, and inconsistencies can creep in.
Thesis: encapsulate shared styles with a mixin that accepts a content block
Stylus mixins can receive a block of declarations via the special @content placeholder. By moving the common properties into a mixin and yielding the unique declarations inside @content, you keep the shared logic in one place while still allowing each variant to inject its own styles.
Worked example: a button base mixin
First, define a mixin that takes the variable parts (padding and background) and yields a content block for any additional rules:
// button-base.styl
button-base($padding, $bg)
padding $padding
background $bg
border none
cursor pointer
font-size 1rem
@content // inject any extra declarations passed by the caller
Now create two button variants that reuse the mixin and pass a hover block via @content:
// buttons.styl
@import 'button-base'
.primary-button
button-base(12px, #0069d9)
@content
&:hover
background darken(#0069d9, 10%)
.secondary-button
button-base(12px, #fff)
@content
&:hover
background #f0f0f0
border 1px solid #ccc
When Stylus compiles this, the @content block is placed exactly where the mixin yields it, producing CSS equivalent to writing the hover rules directly inside each selector:
/* compiled CSS (simplified) */
.primary-button {
padding: 12px;
background: #0069d9;
border: none;
cursor: pointer;
font-size: 1rem;
}
.primary-button:hover {
background: #0052a3;
}
.secondary-button {
padding: 12px;
background: #fff;
border: none;
cursor: pointer;
font-size: 1rem;
}
.secondary-button:hover {
background: #f0f0f0;
border: 1px solid #ccc;
}
Trade‑off and limitation
While this pattern reduces duplication, over‑using @content can lead to deep selector nesting if you pass complex blocks that themselves contain further mixins. Deep nesting increases specificity, making overrides harder, and can bloat the output CSS if the same mixin is instantiated many times with large blocks. Additionally, some CSS optimizers (e.g., PurgeCSS) treat mixin definitions as static code and may not tree‑shake unused mixins, so the definitions remain in the source even if never called.
To check whether you are introducing problematic nesting, compile your Stylus file and inspect the generated CSS:
stylus buttons.styl -o buttons.css(run in your project directory; requires Stylus installed globally or vianpx).- Open
buttons.cssand look for selectors with more than three levels (e.g.,.parent .child .grandchild). If you see many such selectors, consider flattening the mixin or limiting the complexity of the passed content block. - Compare file size with a manually duplicated version:
wc -c buttons.cssversus the size of a file where you wrote the button rules without mixins. A noticeable reduction indicates the mixin is helping; if the sizes are similar, the abstraction may not be worth the added indirection.
Actionable closing
Start by identifying a repeated pattern in your stylesheet—padding, font‑size, or a base reset—and extract it into a mixin that yields @content. Use the mixin for at least two variants to verify the reuse. After each change, run the compilation step above and spot‑check the output for unexpected nesting or size growth. If the generated CSS stays clean and the file size drops, you have a maintainable abstraction; otherwise, reconsider the block complexity or revert to a simpler mixin without @content.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.