Sass Basics: @-rules and Directives

Reggie Dawson
Reggie Dawson
Share

The @-Rules and directives in Sass are backbone features that you should at least know about, especially when it concerns the @import rule. Some of these @-rules are extensions of CSS @-rules while others are Sass specific directives. Either way it is best you know what these rules are for and how they work if you are going to be working with Sass.

@import

Sass extends the CSS @import rule so it can import SCSS/Sass files. Normally we use this rule to import our Sass into one master file. We include this master file as our main CSS file in a project to use all of the consolidated rules. Importing a file gives access to any mixins or variables included in the files.

Sass by default looks for other Sass files in the current directory and then in the Sass file directory under Rails. You can also specify additional directories using the load paths option. If you are using Compass you can specify the directory by changing the sass_dir value in config.rb.

@import looks for a Sass file to import but will compile to a CSS @import rule under the following conditions:

  • The file extension is .css
  • The filename begins with htp://
  • The filename is a url()
  • The @import has media queries

If the extension of the file is .scss or .sass the file will be imported. If there is no extension Sass will try and find a file that matches the name and the proper extension. For example:

@import "sample.scss";

@import "sample";

Both of these @import statements are valid and will import the sample.scss file. The second import would also import sample.sass if it existed.

We can also import multiple files in one @import statement by including the files in a comma separated list.

@import "sample1", "sample2", "sample3";

Care must be taken when importing files, as they must be imported in a correct order. For example, lets say we have a file called myVariables that includes the variables in our project. If we have another file called myStyles that uses these variables, the myVariables file must be imported first.

@import "myStyles";
@import "myVariables";

If we import in this order we will get an error as myStyles will try and use variables that have not yet been defined.

@import "myVariables";
@import "myStyles";

This is the correct way to import as the variables referenced in the myStyles file have already been imported.

Partials @import

When you import a SCSS/Sass file it will compile to a CSS file of the same name. Normally we want to import separate SCSS/Sass files into one master CSS file versus multiple CSS files. In order to accomplish this we need to @import the files as partials. We make a SCSS/SASS file into a partial by adding an underscore in front of the name. The underscore tells Sass not to compile the file as an individual CSS file, but to merge it with the current file that contains the @import statement.

When we import these partials we do not have to include the underscore. Lets say we changed myVariables into _myVariables. We would import the file the same way.

@import "myVariables";

The difference is that no myVariables.css file will be created, the file will be merged with the main CSS file. It is important to note that you cannot include a partial and non-partial with the same name in a directory. We could not have _myVariables.scss and myVariables.scss in the same location.

Nested @import

Most of the time we will have our @import at the top level of our document we can include them inside our rules. The imported rules will be nested where they were imported. For example lets say we have a file name test with the following rule

.try {
  color: blue;
}

We can nest this import in our main file.

#why {
  @import "test";
}

This will compile to:

#why .try {
  color: blue;
}

Directives such as @mixin that are only allowed at the base level of a document cannot be in files that are nested imports. By the same token you cannot nest @import inside mixins or control directives.

@media

@media behaves the same as CSS @media rules with the exception that they can be nested inside of CSS rules. When @media directives are nested in CSS rules they will bubble up to the top level of the stylesheet.

.container {
  width: 60%;
  @media (min-width: 200px) and (max-width:600px) {
    width: 100%;
  }
}

Will compile to:

.container {
  width: 60%;
}
@media (min-width: 200px) and (max-width: 600px) {
  .container {
    width: 100%;
  }
}

As you can see we get a separate rule for our media query even though it was nested inside of the .container class. We can also nest @media queries inside of another. The queries will be combined using and.

@media screen {
  .main {
    @media (max-width: 600px) {
      width: 100%;
    }
    @media (min-width: 700px) {
      width: 70%;
    }
  }
}

Which gives us

@media screen and (max-width: 600px) {
  .main {
    width: 100%;
  }
}
@media screen and (min-width: 700px) {
  .main {
    width: 70%;
  }
}

As you can see two media queries were created. Lastly we can use Sass expressions such as variables, functions, and operators for feature names and values.

$format: screen;
$mobile: 500px;
$tablet: 800px;
$desktop: 1200px;

@media #{$format} {
  .menu {
    @media (max-width: $mobile) {
      width: 100%;
    }
    @media (max-width: $tablet) {
      width: 60%;
    }
    @media (max-width: $desktop) {
      width: 30%;
    }
  }
}

As you can see we are using interpolation with our $format variable and nesting our queries. We use the different device variables to build the rest of our queries. This give us:

@media screen and (max-width: 500px) {
  .menu {
    width: 100%;
  }
}
@media screen and (max-width: 800px) {
  .menu {
    width: 60%;
  }
}
@media screen and (max-width: 1200px) {
  .menu {
    width: 30%;
  }
}

@extend

Sometimes when styling a page you may have an element that should have all the styles of another element as well as styles of its own. Lets say we had two classes for text, one regular and one for emphasized text.

.main {
  color:  black;
  font-size: 12px;
}
.emphasis {
  font-weight: bold;
}

This works well enough but in order to use emphasized text we have to do this:

<div class="main emphasis">

Remember we can use Sass to lessen the amount of typing we have to do. The @extend directive allows us to have one element inherit the styles of another.

.master {
  color:  black;
  font-size: 12px;
}
.emphasis {
  @extend .master;
  font-weight: bold;
}

We have used @extend to rewrite the styles from above, which gives us:

.master, .emphasis {
  color: black;
  font-size: 12px;
}

.emphasis {
  font-weight: bold;
}

As you can see .emphasis is included with .master as well as having styles that only apply to emphasized text. Now to use this class we just have to include the .emphasis class.

With the @extend directive we can extend complex selectors, have multiple @extends, chain @extends, and much more. I could write a whole article on @extends, for more information on @extends check out the Sass documentation.

Use @extend with caution as the outputted CSS can become bloated and because of how the directive works you could be creating some really bad CSS. Hugo has written a post on why he avoids using @extend and more in-depth post on it too.

@at-root

The @at-root directive creates rules at the root of the document instead of being nested in their parent element.

.top {
  .first {
    font-size: 12px;
  }
  @at-root {
    .second {
      font-size: 14px;
    }
    .third {
      font-size: 16px;
    }
  }
  .fourth {
    font-size: 18px;
  }
}

Which compiles to:

.top .first {
  font-size: 12px;
}
.second {
  font-size: 14px;
}
.third {
  font-size: 16px;
}
.top .fourth {
  font-size: 18px;
}

The @at-root directive works on a single line or a block of selectors. As you can see the selectors nested inside @at-root are at the root of the document. The other selectors are nested inside .top.

The @at-root directive also allows you to move outside of directives by using (without:...) or (with:...). For example.

@media print {
  .copy {
    color: black;
    @at-root (without: media) {
      width: 100%;
    }
  }
}

Which give us:

@media print {
  .copy {
    color: black;
  }
}
.copy {
  width: 100%;
}

The @at-root directive also has a without, which could allow us to create a separate style without the @media query.

@debug

The @debug directive prints the value of a Sass expression to the standard error output stream. For example:

@debug 10px + 20px;

When I save the file the output is written to the output stream of my watch command.

1 DEBUG: 30px

@warn

The @warn directive prints the value of a Sass expression to the standard error output stream.

$wrn: 20px;
@warn "#{$wrn}";

It will display the value of the expression as well as the line number of the warning.

@error

The @error directive gives the value of a Sass expression as an error, again to the standard error stream

$test: 1px;
@error "#{$test}";

This will display error, line number, and value in the standard error stream.

Conclusion

We have highlighted a number of @-Rules and Directives you may have not known about. You may not find much use for them but it is always good to know the full capabilities of your tools.

Frequently Asked Questions (FAQs) about Sass Basics, Rules, and Directives

What are the basic rules of Sass?

Sass, which stands for Syntactically Awesome Stylesheets, is a CSS preprocessor that helps to make the process of designing web pages more efficient. The basic rules of Sass include the use of variables, nesting, mixins, inheritance, and operators. Variables allow you to store values that you want to reuse throughout your stylesheet. Nesting enables you to nest your CSS selectors in a way that follows the same visual hierarchy of your HTML. Mixins are like functions that you can create and reuse throughout your stylesheet. Inheritance is a feature that allows you to share a set of CSS properties from one selector to another. Operators are used for mathematical operations.

How do Sass directives work?

Directives in Sass are special instructions that are executed during the compilation process. They start with the “@” symbol and are followed by the directive’s name and expression. Some of the most common Sass directives include @import, @media, @extend, @at-root, @debug, @warn, @error, and control directives like @if, @for, @each, and @while. These directives allow you to import other Sass files, create media queries, extend other selectors, control the scope of styles, debug your code, display warnings, throw errors, and create complex logic in your stylesheets.

What is the difference between Sass and SCSS?

Sass and SCSS are both syntaxes for the Sass preprocessor. The main difference between them is the syntax. Sass uses an indented syntax where CSS blocks are indented to indicate nesting, and it doesn’t use semicolons or braces. On the other hand, SCSS uses a syntax similar to CSS, with braces to denote code blocks and semicolons to separate lines within a block.

How can I use variables in Sass?

Variables in Sass are declared using the “$” symbol followed by the variable’s name and value. For example, you can declare a variable for a color like this: $primary-color: #333;. Then, you can use this variable throughout your stylesheet like this: body { background-color: $primary-color; }.

How can I use mixins in Sass?

Mixins in Sass are declared using the @mixin directive followed by the mixin’s name and optionally some arguments. For example, you can create a mixin for a transition effect like this: @mixin transition($property, $duration: 0.3s) { transition: $property $duration; }. Then, you can include this mixin in your selectors using the @include directive like this: .box { @include transition(width); }.

How can I use inheritance in Sass?

Inheritance in Sass is achieved using the @extend directive. This directive allows you to share a set of CSS properties from one selector to another. For example, if you have a .button class with some styles and you want to create a .primary-button class with the same styles plus some additional ones, you can do it like this: .primary-button { @extend .button; background-color: blue; }.

How can I use operators in Sass?

Operators in Sass allow you to perform mathematical operations. The available operators are +, -, *, /, and %. You can use them to calculate values for your CSS properties. For example, you can calculate the width of an element like this: .element { width: 100% / 3; }.

How can I use control directives in Sass?

Control directives in Sass allow you to create complex logic in your stylesheets. The available control directives are @if, @for, @each, and @while. For example, you can create a loop to generate classes for a grid system like this: @for $i from 1 through 12 { .col-#{$i} { width: 100% / $i; } }.

How can I debug my Sass code?

Sass provides several directives for debugging: @debug, @warn, and @error. The @debug directive prints the value of an expression to the standard error output. The @warn directive prints a warning message to the standard error output. The @error directive throws an error and stops the compilation process.

How can I control the scope of styles in Sass?

The @at-root directive in Sass allows you to control the scope of styles. This directive causes one or more rules to be emitted at the root of the document, rather than being nested beneath their parent selectors. For example, you can use it to create a global modifier class for a component like this: .component { @at-root .component–modifier & { background-color: blue; } }.