Sass 3.2 added the @content
directive, which allows
us to pass a content block into a mixin.
@mixin apply-to-ie6-only {
* html {
@content
}
}
@include apply-to-ie6-only {
#logo {
background-image: url(/logo.gif);
}
}
Generates:
* html #logo {
background-image: url(/logo.gif);
}
We can use it anywhere that declarations need to be wrapped in outer-scoped selectors, and many places where declarations are duplicated.
Media Queries
We can inline our media queries rather than maintaining separate, device-specific stylesheets, but writing queries over and over can get pretty unwieldy. We can simplify them by passing a content block into a mixin that wraps a query.
@mixin media($width) {
@media only screen and (max-width: $width) {
@content;
}
}
@include media(320px) {
background: red;
}
Generates:
@media only screen and (max-width: 320px) {
background: red;
}
This becomes especially helpful for long, highly specific media queries, like the HiDPI mixin we use in Bourbon.
You can see our full @media
mixin in Neat.
Keyframes
Keyframes are a good example of content duplication. Rather than rewriting the declarations for each vendor-specific selector, we can instead write a mixin to do it for us.
@mixin keyframes($name) {
@-webkit-keyframes #{$name} {
@content;
}
@-moz-keyframes #{$name} {
@content;
}
@keyframes #{$name} {
@content;
}
}
@include keyframes(fadeIn) {
from {
opacity: 0%;
}
to {
opacity: 100%;
}
}
Generates:
@-webkit-keyframes fadeIn {
from {
opacity: 0%;
}
to {
opacity: 100%;
}
}
@-moz-keyframes fadeIn {
from {
opacity: 0%;
}
to {
opacity: 100%;
}
}
@keyframes fadeIn {
from {
opacity: 0%;
}
to {
opacity: 100%;
}
}
This is also used in Bourbon.
Context Specificity
I just picked up a project from Reda Lemeden, who wrote a pair of clever mixins to modify components for a given context.
Instead of creating many .component--modifiers
or chaining modifying classes,
we can better separate our concerns by defining a style’s context specificity.
@mixin create-context($classes...) {
@each $class in $classes {
.#{$class} & {
@content;
}
}
@mixin context--alternate-template {
@include create-context(about, blog) {
@content
}
}
.header {
height: 12em;
background: red;
@include context--alternate-template {
background: green;
}
}
Generates:
.header {
height: 12em;
background: red;
}
.about .header {
background: green;
}
.blog .header {
background: green;
}
Getting BEMy
Sass 3.3 adds the @at-root
directive and improved &
s. The former allows us
to nest declarations in Sass, but compile them to the stylesheet’s root. The
latter appends any following text directly to the parent’s selector.
These can be used with @content
to simplify writing BEM syntax. Thanks
to Scott Kellum for the
original implementation.
@mixin element($name) {
@at-root #{&}__#{$name} {
@content;
}
}
@mixin modifier($name) {
@at-root #{&}--#{$name} {
@content;
}
}
.block {
color: red;
@include element(element) {
color: green;
@include modifier(modifier) {
color: blue;
}
}
}
Generates:
.block {
color: red;
}
.block__element {
color: green;
}
.block__element--modifier {
color: blue;
}
In Conclusion
@content
is just one of many Sass directives that can empower us to remove
duplication in our SCSS, and think more creatively about its organization and
implementation. Learn more by reading the Sass directives
documentation.