Table of Contents
Have you ever wanted to know some Sass tricks? Then, this article is for you. Is the @content directive still a bit of a mystery for you? Then, you are on the right place. In this article, you will learn what you need to finally understand how @content directive works. After that, you will learn about Sass directives that will help you debug your code. With this final lesson, you will know enough Sass to be dangerous. Hopefully, in a good sense. Let’s begin.
Content directive
A lot of people asked me about one specific thing they saw in The Beginner’s Guide to Learn Sass – Mastering the Basics of Sass, in part about mixins and extends. What is this thing we are talking about? In short, it is @content directive. For a lot of people, who read that article, this Sass feature was a bit hard to understand. For this reason, I decided to start these Sass tricks article with an exploration of @content directive. I hope this will help you understand this feature and use it.
Mixins, @content directive and no additional styles
The @content directive works in a simple way. This directive allows you to pass a block of styles to the mixin you want to use. You put this block of styles between the curly brackets. It is just like working with regular CSS selector. Well, nested rather a selector in Sass. Then, when compiled, these styles will appear at the place you put the @content directive within the mixin. If mixin doesn’t contain any other styles. Then, these styles will be the only content of compiled CSS.
Sass:
// Simple mixin for retina images that will generate necessary media query @mixin retina-image { @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { @content; } } // Using retina-image mixin div { @include retina-images { background: url(image@2x.png); } }
CSS:
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { div { background: url(image@2x.png); } }
Mixins and @content directive with additional styles
Now, how about to make this more interesting? This is about Sass tricks. Why should we use only @content directive and nothing else? Also, we should think about some scenario that is more like those from the real world. In the real world (projects), it is very likely that you will want to add some default styles to the mixin, along with the custom. So, what if you have styles above or below the @content directive? Then, these styles will appear above or below the styles you provided through the directive.
Sass:
// Mixin for retina image with additional styles // Quick note: yes, Sass will compile those CSS comments inside the mixin in CSS as well. @mixin retina-images { @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { /* Content block begin */ @content; /* Content block end */ background-repeat: no-repeat; background-position: center; background-size: cover; } } div { @include retina-images { background: url(image@2x.png); } }
CSS:
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { div { /* Content block begin */ background: url(image@2x.png); /* Content block end */ background-repeat: no-repeat; background-position: center; background-size: cover; } }
Mixins with multiple @content directives
Before we move to the next of Sass tricks, there is one thing I want to mention. If you use @content directive multiple times, Sass will repeat it as well. This can be quite useful. For example, it can help you create prefixed versions of your code. Although, using autoprefixer directly or through postCSS plugin is much better way to do this. This way, you don’t have to watch for outdated prefixes. Anyway, let’s say you want to create mixin for creating short and simple keyframe for fading animation.
Sass:
// Simple mixin for generating keyframes for animations @mixin keyframe($keyframe-name) { @-webkit-keyframes #{$keyframe-name} { @content; } @-moz-keyframes #{$keyframe-name} { @content; } @keyframes #{$keyframe-name} { @content; } } // Use mixin for generating keyframes for animations @include keyframe(fadeIn) { from { opacity: 0%; } to { opacity: 100%; } }
CSS:
@-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%; } }
Let’s spice these Sass tricks up with a bit more complex mixin you may want to use. We can use multiple @content directives and @if statements to generate media queries for your grid.
Sass:
@mixin media-query($media) { @if $media == mobile { @media only screen and (max-width: 479px) { @content; } } @else if $media == tablet { @media only screen and (min-width: 480px) and (max-width: 767px) { @content; } } @else if $media == desktop { @media only screen and (min-width: 768px) and (max-width: 991px) { @content; } } @else if $media == large { @media only screen and (min-width: 992px) { @content; } } } .container { width: 100%; @include media-query(mobile) { max-width: 460px; } @include media-query(tablet) { max-width: 750px; } @include media-query(desktop) { max-width: 970px; } @include media-query(large) { max-width: 1170px; } }
CSS:
.container { width: 100%; } @media only screen and (max-width: 479px) { .container { max-width: 460px; } } @media only screen and (min-width: 480px) and (max-width: 767px) { .container { max-width: 750pxpx; } } @media only screen and (min-width: 768px) and (max-width: 991px) { .container { max-width: 970px; } } @media only screen and (min-width: 992px) { .container { max-width: 1170px; } }
Interpolation
In the mixin for keyframe, you saw #{$keyframe-name}. This is something called interpolation. And, since we are talking about Sass tricks this is a good time to quickly explore this sass feature. In short, interpolation allows you to use variables and parameters in selectors, classes, IDs and property values. In the last case, interpolation will help you use Sass as plain CSS. This is very useful in situations that Sass would otherwise take as a sign to perform computation.
Sass:
// Create variables for later use through interpolation $element: btn; $property: border; $font-size: 16px; $line-height: 1.414; // Use of interpolation to generate classname, CSS value and property .#{$element} { font: #{$font-size} / #{$line-height}; #{$property}-color: #3498db; }
CSS:
// Font values with interpolation .btn { font: 16px / 1.414; border-color: #3498db; }
Sass:
// Font values without interpolation // Note: ".$element {" would cause an error .#{$element} { font: $font-size / $line-height; #{$property}-color: #3498db; }
CSS:
.btn { font: 11.31541726px; /* Value of font is a result of 16px / 1.414 (Sass divided those numbers)*/ border-color: #3498db; }
Sass:
// Create mixin for margin with loop that will use interpolation // Using triple dots will make Sass to treat the variable as a list @mixin margin($values...) { @each $value in $values { padding: #{$value}; } } // Using margin mixin div { @include margin(12px 16px 8px); }
CSS:
div { padding: 12px 16px 8px; }
Debugging in Sass
Let’s explore another topic that will teach you a couple of useful Sass tricks. Sass comes with set of directives you can use for debugging your Sass code. These directives are @debug, @error and @warn. Fortunately, all these directive share the same syntax – @directive something; (replace the “@directive” with @debug, @error or @warn).. Also, there is no limitation to what you can use with these directives. You can use strings, maps, lists, numbers or whatever you want.
However, a lot of developers usually use these directives to add context to the problem. So, it is very likely that you will want to use a string. One thing, these directives for debugging also support interpolation. So, if you want to use string with specific variable, you can.
Sass:
// Debug directives with string @debug "Example of debug message"; @error "Example of error message"; @warn "Example of warn message"; // Debug directives with interpolation @debug "There is some issue with #{$variable}."; @error "Error - #{$variable} does not exist"; @warn "This variable (#{$variable}) will be deprecated in the next version";
It is good to know a handful of Sass tricks like these directives. However, you also need to know when to use which. The first directive, @debug directive, is the least intrusive of all three. When something trigger this directive, it will print the value of whatever Sass expression you used to the console. Nothing more will happen. In other words, you can continue in work knowing that there is something you should take a look at in the future.
Debug directive
This “silent” behavior makes @debug directive useful for working on personal projects. For example, let’s say you have a snippet of complex code and you want to know what one of your variables contains at a specific moment. Then, you can use @debug directive to find it out. If you are familiar with JavaScript, @debug is similar to console.log(). Again, it will not stop executing the code or prevent it from running. It will only gently notify you.
Sass:
// Variable $font-base: 16px; // Simple list $media-queries: 480px 768px 992px; // Map with colors $palette-custom: ( black: #212121, gold: #ba8747, red: #c0392b, violet: #8d38c9 ); // @debug directives body { @debug $media-queries; // list @debug $palette-custom; // map @debug $font-base; // value @debug (480px / 16); // math expression @debug "This is not the best way to write CSS"; // string }
Console:
_main.scss:32 DEBUG: 480px 768px 992px _main.scss:33 DEBUG: (black: #212121, gold: #ba8747, red: #c0392b, violet: #8d38c9) _main.scss:34 DEBUG: 16px _main.scss:35 DEBUG: 30px _main.scss:36 DEBUG: This is not the best way to write CSS
Error directive
The second directive and another tool for your Sass tricks toolkit is @error directive. This directive is bolder than its sibling we discussed above. Sass @error directive will print a string of text about some fatal error in console and it will also stop the Sass compiler. In other words, when something trigger this directive, you will know about it. This makes @error directive ideal for cases when you want to send the developer important message and force him to correct the mistake immediately.
A good example is notifying the develop about using wrong type of value or doing something wrong. For example, let’s say you have a function accepts specific type or format of input. Then, you can use @error directive to stop the compiler and notify the developer that he used wrong type or format of value. This way, it is unlikely that he will accidentally overlook his mistake. If you have some function that for generating styles from a map, based on key / value pair, you can use @error directive to make sure that specific key is in the map.
Also, don’t worry that finding the specific line will be difficult. The error message provided by Sass will include specific line number where that fatal error is.
Sass:
@function color-grabber($color) { @if has-key($color-palette, $color) { @return map-get($color-palette, $color); } @error "Invalid color used: #{$color}."; }
Warn directive
The last of the directives, @warn, is significantly less insistent than @error directive. As its sibling, it will also send you a message to the compiler with specific line and file where the warning message I located. However, it will let the compiler to finish its job without stopping or breaking it. So, like with @debug, you can continue in work. This makes @warn directive a good choice for implementing messages or notifications about deprecated code.
Another good use of @warn directive is to let the developer know about the best practice you and your team uses. One thing I have to mention is that messages sent by @warn directive will not appear if you use –quite flag. So, if you know that someone in your team, or even you, is using this flag, you should use @error directive instead. Otherwise, it can happen that you or your teammate will never see the message.
Sass:
// Function with @warn directive @function remy($target) { @if unit($target) != px { @warn 'Please, use only pixel values in `remy()` function.'; } @else { @return ($target / $font-size-base) * 1rem; } } element { font-size: remy(16em); }
Console:
WARNING: Please, use only pixels values in `remy()` function. Backtrace: src/scss/_tools/_functions.scss:9, in function `remy` src/scss/_tools/_functions.scss:25
Closing thoughts on Sass tricks & tips
Let’s end these Sass tricks with a couple of words about best practices. Be smart and think ahead. Think about how the compiler will compile your code. Then, ask yourself if the final CSS code is really in the shape and form you would write it. Whenever you will want to nest something, always ask yourself, is this really necessary? Is there a way you can achieve the same result will less selectors? Remember that you don’t have to nest everything just because Sass allow you to do it.
Stay away from extremes. You can use Sass and these Sass tricks to take the quality of your code to another level. However, you can also overuse these Sass tricks and make your code much worse then it was before. This is quite overused quote, but I will say it anyway. With great power comes great responsibility. Sass can give you this power. So, be responsible. Again, when you write in Sass think how the code will look like compiled. And, when in doubt, use your common sense.
Another thing I would suggest is learning about everything Sass can provide you with and then at least trying it. There is some reason why Sass has certain feature. And, there are also situations when one feature do a better job than another. Mixins and extends are one example. In one case it might be better to use mixin while in other extends. Learn about these features and other Sass tricks to know when to use which.
Finally, use Sass along with advanced CSS skills. Ask yourself, can you simplify your Sass code without adding extra classes? Imagine that you could not touch the HTML. Can you use things such as direct child elements, sibling, adjacent or nth-of-type selectors? If so, do it. Just because you know Sass and handful of Sass tricks doesn’t mean you should not learn how to use CSS properly. Master the rules of CSS first. Then, you can think about nesting selectors.
If you liked this article, please subscribe so you don't miss any future post.
If you'd like to support me and this blog, you can become a patron, or you can buy me a coffee 🙂