Content blocks: @content
Arguments pass single values into a mixin. Sometimes you need to pass a whole block of styles — for example, "these declarations, but only on wide screens". The @content rule marks the place inside a mixin where that block is inserted.
A mixin with @content
The most common example is a breakpoint mixin. Add it to styles/abstracts/_mixins.scss:
// styles/abstracts/_mixins.scss
@mixin tablet {
@media (min-width: 768px) {
@content;
}
}When you include it, write a block in curly braces after the name. That block replaces @content:
// styles/components/_cards.scss
@use "../abstracts/mixins";
.cards {
display: grid;
gap: 16px;
@include mixins.tablet {
grid-template-columns: 1fr 1fr;
}
}// styles/main.scss
@use "components/cards";.cards {
display: grid;
gap: 16px;
}
@media (min-width: 768px) {
.cards {
grid-template-columns: 1fr 1fr;
}
}The media query ended up outside .cards, and the selector was repeated inside it — the same as nested media queries in the lesson about nesting.
A breakpoint as an argument
Separate mixins for each size are repetitive. Pass the width as an argument with a default value:
// styles/abstracts/_mixins.scss
@mixin from($width: 768px) {
@media (min-width: $width) {
@content;
}
}// styles/components/_cards.scss
@use "../abstracts/mixins";
.cards {
display: grid;
gap: 16px;
@include mixins.from {
grid-template-columns: 1fr 1fr;
}
@include mixins.from(1024px) {
grid-template-columns: 1fr 1fr 1fr;
}
}// styles/main.scss
@use "components/cards";.cards {
display: grid;
gap: 16px;
}
@media (min-width: 768px) {
.cards {
grid-template-columns: 1fr 1fr;
}
}
@media (min-width: 1024px) {
.cards {
grid-template-columns: 1fr 1fr 1fr;
}
}<style>
.cards {
display: grid;
gap: 16px;
}
@media (min-width: 768px) {
.cards {
grid-template-columns: 1fr 1fr;
}
}
@media (min-width: 1024px) {
.cards {
grid-template-columns: 1fr 1fr 1fr;
}
}
</style>
<div class="cards">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
</div>Change the width of the preview or the browser window: one column, then two, then three. In the lesson about maps the widths move into one list of named breakpoints.
Where @content can be used
@content is not limited to media queries. Any wrapper fits: a hover state only for devices with a mouse, a dark-theme selector, a @supports check:
// styles/abstracts/_mixins.scss
@mixin on-hover {
@media (hover: hover) {
&:hover {
@content;
}
}
}Inside .btn, @include mixins.on-hover { background: black; } produces .btn:hover wrapped in a media query, so touch screens do not get a "stuck" hover.
Common mistake
If you pass a block to a mixin that has no @content, Sass stops with the error Mixin doesn't accept a content block. The reverse situation is silent: a mixin with @content included without a block simply inserts nothing there. When a breakpoint mixin seems to do nothing, check that the block in braces is really there.