Published: December 15, 2023
I feel like an uber-efficient-superhuman dev when I write or find a really good Sass mixin.
If you’re unfamiliar, a mixin is simply a block of code that can accept arguments and output styling rules that can be reused over and over with a simple one-line directive. Mixins are unique to Syntactically Awesome Stylesheets (Sass), a CSS pre-processing language.
Below i’ve curated a list of 6 Sass mixins that save me time on almost any project:
I loathe writing font faces — it’s one of many tasks I regularly fumble. Use this mixing to markup all your project fonts in flash, even if you've got loads of formats.
Mixin:
=font-face($name, $url, $weight, $style) {
@font-face {
font-family: quote($name);
src: url('../../fonts/#{$url}.woff2') format('woff2'), url('../../fonts/#{$url}.woff') format('woff'), url('../../fonts/#{$url}.ttf') format('truetype');
font-weight: $weight;
font-style: $style;
font-display: swap;
}
}
Usage:
+font-face('Open Sans', 'OpenSans-Regular', 400, normal)
+font-face('Open Sans', 'OpenSans-Italic', 400, italic)
+font-face('Open Sans', 'OpenSans-SemiBold', 600, normal)
+font-face('Open Sans', 'OpenSans-SemiBoldItalic', 600, italic)
+font-face('Open Sans', 'OpenSans-Bold', 700, normal)
+font-face('Open Sans', 'OpenSans-BoldItalic', 700, italic)
Output:
@font-face {
font-family: "Open Sans";
src: url(../fonts/OpenSans-Regular.woff2) format("woff2"), url(../fonts/OpenSans-Regular.woff) format("woff"), url(../fonts/OpenSans-Regular.ttf) format("truetype");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Open Sans";
src: url(../fonts/OpenSans-Italic.woff2) format("woff2"), url(../fonts/OpenSans-Italic.woff) format("woff"), url(../fonts/OpenSans-Italic.ttf) format("truetype");
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Open Sans";
src: url(../fonts/OpenSans-SemiBold.woff2) format("woff2"), url(../fonts/OpenSans-SemiBold.woff2) format("woff"), url(../fonts/OpenSans-SemiBold.ttf) format("truetype");
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Open Sans";
src: url(../fonts/OpenSans-SemiBoldItalic.woff2) format("woff2"), url(../fonts/OpenSans-SemiBoldItalic.woff) format("woff"), url(../fonts/OpenSans-SemiBoldItalic.ttf) format("truetype");
font-weight: 600;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Open Sans";
src: url(../fonts/OpenSans-Bold.woff2) format("woff2"), url(../fonts/OpenSans-Bold.woff) format("woff"), url(../fonts/OpenSans-Bold.ttf) format("truetype");
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Open Sans";
src: url(../fonts/OpenSans-BoldItalic.woff2) format("woff2"), url(../fonts/OpenSans-BoldItalic.woff) format("woff"), url(../fonts/OpenSans-BoldItalic.ttf) format("truetype");
font-weight: 700;
font-style: italic;
font-display: swap;
}
This one is great for making a quick full width pseudo element inside a fixed width container. It’s ideal when you are faced with markup constraints.
Mixin:
=full-width($bg-color: transparent, $height: 100%) {
background-color: $bg-color;
content: "";
height: $height;
left: calc(-50vw + 50%);
position: absolute;
top: 0;
width: 100vw;
}
Usage:
.call-to-action {
&::before {
+full-width(#ff7878, 200px)
}
}
Output:
.call-to-action::before {
background-color: #ff7878;
content: "";
height: 200px;
left: calc(-50vw + 50%);
position: absolute;
top: 0;
width: 100vw;
}
This mixin provides a super clean way to attribute dark mode styles to any combination of selectors. The dark-mode boolean variable will allow you to turn dark mode styles on and off globally (this is super useful for debugging). This code also has excellent browser support.
Mixin:
$dark-mode: true;
=dark-mode {
@if ($dark-mode) {
@media (prefers-color-scheme: dark) {
@content;
}
}
}
Usage:
body {
color: #000000;
background-color: #ffffff;
+dark-mode {
color: #ffffff;
background-color: #000000;
}
}
Output:
body {
color: #000000;
background-color: #ffffff;
}
@media (prefers-color-scheme: dark) {
body {
color: #ffffff;
background-color: #000000;
}
}
Crucial to almost any project, I use this mixin to write mobile-first media queries legibly. It’s also super easy to add more custom widths as your project evolves and keep them all in one place.
Mixin:
$desktop: 1024px;
$tablet: 768px;
$mobile: 480px;
=respond-to($media) {
@if $media == desktop-and-up {
@media only screen and (min-width: $desktop) {
@content;
}
} @if $media == desktop-and-down {
@media only screen and (max-width: $desktop - 1) {
@content;
}
} @else if $media == tablet-and-up {
@media only screen and (min-width: $tablet) {
@content;
}
} @else if $media == tablet-and-down {
@media only screen and (max-width: $tablet - 1) {
@content;
}
} @else if $media == small-and-up {
@media only screen and (min-width: $mobile) {
@content;
}
}
Usage:
body {
font-size: 16px; /* Applied to everything small and down (mobile first) */
+respond-to(tablet-and-up) {
font-size: 18px;
}
+respond-to(desktop-and-up) {
font-size: 20px;
}
}
Output:
body {
font-size: 16px; /* Applied to everything small and down (mobile first) */
}
@media only screen and (min-width: 768px) {
body {
font-size: 18px;
}
}
@media only screen and (min-width: 1024px) {
body {
font-size: 20px;
}
}
Adding truly responsive font sizing can be fiddly which is one of the reasons it's not common practice. This mixin makes it super easy.
Mixin:
=font-size($min-size, $viewport-min, $viewport-max, $max-size) {
font-size: clamp(#{$min-size}, calc((100vw - #{$viewport-min}) * 1vw + #{$min-size}), #{$max-size});
}
Usage:
body {
+font-size(16px, 350px, 1200px, 24px);
}
Output:
body {
font-size: clamp(16px, calc((100vw - 350px) * 1vw + 16px), 24px);
}
This is my favourite of them all, it gives you a super fast way to declare an aspect ratio that will work across all browsers. You will need to use the container as a selector for this to work.
You can either add the selector of a specific child of the parent into the second argument or leave it blank and the mixin will default to the first child of the container. Thanks to Jonathan for this one.
Mixin:
=fluid-aspect($ratio: 1 1, $selector: "> :first-child") {
$selector: unquote($selector);
padding-bottom: percentage(nth($ratio, 2) / nth($ratio, 1));
position: relative;
#{$selector} {
left: 0;
height: 100%;
position: absolute;
top: 0;
width: 100%;
}
}
Usage:
.my-container {
+fluid-aspect(16 9);
}
/* Or */
.my-container {
+fluid-aspect(4 3, iframe);
}
Output:
.my-container {
padding-bottom: 56.25%;
position: relative;
}
.my-container > :first-child {
left: 0;
height: 100%;
position: absolute;
top: 0;
width: 100%;
}
/* Or */
.my-container {
padding-bottom: 75%;
position: relative;
}
.my-container iframe {
left: 0;
height: 100%;
position: absolute;
top: 0;
width: 100%;
}
I hope one or two of these mixins prove to be as useful for you as they are for me. I find, as a rule, if you are repeating yourself more than twice, make a mixin.