SCSS - tutorial - SCSS @rules (at-rules)

Revision:


Content

SCSS - what they are @ rules available in SCSS @mixin and @include @use @forward @import @function @if, @else, @else if @for @each @while @extend @at-root @error @warn @debug


SCSS - what they are

top

The SCSS at-rules or @ rules provide most of the extra functionality, which SCSS provides, like defining functions and then using them, using loop in your CSS, flow control, and a lot more.

There are different types of at-rules which have a "prefix @", where each of the at-rules available in SCSS is having a special purpose, which makes it even more interesting and easier to code complex styling rules.

If you want to define a function, or use conditional statements, or use a loop in your styling code, or if you simply wish to debug the styling code, using these "@ rules" we can easily do all this, as there are specific @ rules available in SCSS to provide all these features.


@ rules available in SCSS

top

Following are the @ rules available in SCSS:

@use

@forward

@import

@mixin and @include

@function

@if, @else, amd @else if

@for

@each

@while

@extend

@at-root

@error

@warn

@debug

@media


@mixin and @include

top

SCSS mixins are functions used to define styles that can be re-used throughout your stylesheet, thereby allowing you to write reusable styling rules. Write once, use again and again.

You need to write these mixins with some style rules in it and then you can reuse it anywhere in the rest of the stylesheet any number of times. You can create mixins using the @mixin at-rule.

syntax: @mixin <name> {// styling rules} or @mixin name(<arguments...>) {// styling rules}

SCSS mixin can have any name and you can include any valid styling statement in it, just like a function definition.

example 1: mixins

        @mixin center-content() {
            display: flex;
            justify-content: center;
            align-items: center;
        }
    

To use a mixin defined using the @mixin at-rule, we use the @include at-rule. Following is the syntax of using the @include at-rule for using a pre-defined SASS mixin:@include <name> or @include <name>(<arguments...>) , where the name is the name of the mixin and arguments specify the arguments that a mixin accepts.

example 2: calling mixins

        .centered-container {
            @include center-content();
        }
        .centered-container-green {
            @include center-content();
            background: $color-green;
        }
    

example 3: @mixin and @include

        // defining a mixin
        @mixin basic-list{
            margin: 0
            padding: 0
            list-style: none
        }    
        // using a mixin inside another mixin
        @mixin inline-list{
            @include basic-list
        }    
        li{
            display: inline-block
            margin:
            left: -2px
            right: 2em
        }    
        // calling a mixin in simple style rule
        nav ul{
          @include inline-list
        }    
    

The above SCSS code will be transpiled into the following CSS code:

        nav ul {
            margin: 0;
            padding: 0;
            list-style: none;
        }
        nav ul li {
            display: inline-block;
            margin-left: -2px;
            margin-right: 2em;
        }
    

SCSS mixin supports arguments so that you can use them with different values to customize the style rule when you call any mixin.

example 4: mixins with arguments

        @mixin customtextstyle($color, $size){
            color: $color
            font-size: $size
            font-weight: 400
        }    
        .sidebar{
            @include customtextstyle(#999999, 16px)
        }    
    

This will be compiled into the following CSS code:

        .sidebar {
            color: #999999;
            font-size: 16px;
            font-weight: 400
        }
    

We can provide "default values" to the arguments while defining a mixin so that even if the user doesn't provide a value for the argument, the default values are used.

example 5: mixin with default values

        @mixin customtextstyle($color, $size:12px){
            color: $color
            font-size: $size
            font-weight: 400
        }
        .left-sidebar{
            @include customtextstyle(#999999, 16px)
        }
        .right-sidebar{
            @include customtextstyle(blue)
        }
    

This will be compiled into the following CSS code:

        .left-sidebar {
            color: #999999;
            font-size: 16px;
            font-weight: 400
        }
        .right-sidebar {
            color: blue;
            font-size: 12px;
            font-weight: 400
        }
    

While calling SCSS mixin, we generally provide the arguments in the same order in which they were declared when the mixin is defined. But we can also pass the argument values by name while calling the mixin.

example 6: mixin with keyword arguments

        @mixin customtextstyle($color, $size : 12px){
            color: $color
            font-size: $size
            font-weight: 400
        }    
        // calling mixin by providing argument with name
        .sidebar{
            @include customtextstyle(#999999, $size : 16px)
        }    
    

SCSS mixin also supports "arbitrary arguments" which means a mixin can take any number of arguments when it is called. If the last argument in a mixin declaration ends in ...(three dots), then all the extra arguments passed when the mixin is called are passed in the last argument as a list.

example 7: mixin with arbitrary arguments

        @mixin custom-input($height, $selectors...){
            @for $i from 0 to length($selectors)
                #{nth($selectors, $i + 1)}
                padding: 10px
                height: $height
                // generating different border-radius for all
                border-radius: i*5px
        }
        @include custom-input(10px, "input.name", "input.address", "input.zip")
    

The above code is compiled into the following CSS code:

        input.name {
            padding: 10px;
            height: 10px;
            border-radius: 5px;
        }
        input.address {
            padding: 10px;
            height: 10px;
            border-radius: 10px;
        }
        input.zip {
            padding: 10px;
            height: 10px;
            border-radius: 15px;
        }
    

It also makes sense to include our mixins before any other stylesheets besides variables, which we will need.

example 8: mixins

        @import './variables.scss';
        @import './mixins.scss';
        @import './styles.scss';
    

@use

top

SCSS @use at-rule is used to load mixins, functions, and variables defined in other stylesheets, in your stylesheet.

Before the introduction of @use at-rule, SCSS @import at-rule was used for this purpose. Using SCSS @use at-rule enables us to break our stylesheet into multiple meaningful smaller stylesheets and then use them in one another using the SCSS @use at-rule.

We can define SCSS mixins and functions in a separate stylesheet file, and variables with default values in a separate stylesheet file and then in the main stylesheet we can use the SCSS @use at-rule to use the mixins, functions, and variables, etc. defined in other stylesheets. The stylesheets being included are called modules.

syntax: @use '<URL for other stylesheet>'

example 9: @use

        @use 'mixinstyle.scss'
    

A few things to note here: 1/when we include a stylesheet in another stylesheet using the @use at-rule, the style rules will get included exactly once in the compiled CSS, and 2/ the @use statement should be the first statement in the stylesheet; you can have the @forward at-rule or variable declaration before the @use statement, but no styling rule should be specified before this.

example 10: @use

        // style/columns.scss
        row{
            margin: 0 auto
            line-height: 0
        }
        col-12{
            width: 100%
        }
        // styles/textstyle.scss
        h1{
            font-size: 36px
        }    
        p{ 
            font-size: 14px
        }
        // main.scss
        @use 'style/columns'
        @use 'style/textstyle'  
    

When we include some stylesheet into our stylesheet using the @use at-rule, then the name of the stylesheet (filename), which is included, acts as the namespace without the extension. To access the variables, mixins, and functions from another stylesheet(module), which is included in your stylesheet using the @use at-rule, we must follow the following syntax: <namespace>.<variable> or <namespace>.<function>() or @include <namespace>.<mixin>(), where <namespace> is the namespace, which means the filename of the stylesheet included.


@forward

top

SCSS @forward at-rule is used to expose the members of modules(stylesheets) included in a stylesheet using the @use at-rule when the stylesheet is included in another stylesheet.

EXAMPLE: assume we have a stylesheet "_padding.scss" which contains all the style rules(mixins, variables, etc.) for padding, and we include this in our stylesheet "style.scss" using the @use at-rule. Now if we have to create another stylesheet, let's say "newstyle.scss" and we include the "style.scss" in this stylesheet using the @use at-rule, then we won't be able to access the members of "_padding.scss" stylesheet in the "newstyle.scss" stylesheet.

Hence, if we want the members of the stylesheet "_padding.scss" to be accessible in the "newstyle.scss" file we should use the SCSS @forward at-rule to import the "_padding.scss" stylesheet in "style.scss" file. The @forward at-rule will make the members of "_padding.scss" file available in the "style.scss" file as if they were defined in the "style.scss" file. Hence, if any other stylesheet will then include "style.scss" file using the @use at-rule, it will be able to access the members of "_padding.scss" file too.

syntax: @forward 'URL-OF-STYLESHEET'

If we use the @forward at-rule, we can skip using the @use at-rule. We can also have both @use and @forward at-rule for including a single stylesheet as the SCSS engine will only include it once.

SCSS @forward at-rule also works just like the @use at-rule, inluding the members of a stylesheet into another stylesheet. But the @use at-rule hides the members of the included stylesheet from further imports, but @forward at-rule makes the included stylesheet available for further imports too, thereby enabling you to form a hierarchy for stylesheet imports.

If you write both @forward and @use at-rule, you should write the @forward at-rule first followed by the @use at-rule.

example 11: @forward

        /* style/_list.scss */
        @mixin list-style{
          margin: 0
          padding: 0
          list-style: none
        }

        /* main.scss */
        @forward "src/list"


        /* styles.sass */
        @use "main"
        li{
            @include main.list-style
        }
    

This will be compiled into the following CSS:

        li {
            margin: 0;
            padding: 0;
            list-style: none;
        }
    

@import

top

@import makes everything globally accessible in the target file.

A common pattern for SCSS is to create a "main.scss" file which will import each of the other ".scss files".It imports the SCSS files, it directly takes the filename to import.

This enables an endless chain of imported files where it's difficult to trace where your variables and mixins are coming from. It also allows for overlap and makes it difficult to trace back why your perfect css breaks. This is a problem especially with complex file structures and projects with multiple contributors and global libraries, which is why @import is no longer recommended by SCSS.

example 12: @import

        @import './variables.scss';
        @import './styles.scss';
    

The files get imported so any variables used in "styles.scss" will already be loaded. Its useful to keep the order of imports in mind when setting up your projects.


@function

top

SCSS @function at-rule is used to define functions with complex operations, taking in arguments and returning a result. SCSS functions are used to declare complex formulas and behaviors, which can then be used throughout the stylesheet.

syntax: @function <name>(<arguments...>) { ... }

The SCSS function must have a return statement that is specified using the @return at-rule and is used to return a result from the function call.So the overall syntax becomes this: @function <name>(<arguments...>) {// function definition @return <somevalue>}

The @return at-rule can only be used inside a function definition and the function execution ends upon encountering the @return statement, and the result of the function, as specified with the @return at-rule, is returned to the calling statement.

Just like we can provide arguments in SCSS mixins, we can also do so while defining SCSS functions.

example 13: @function with arguments

        @function add($var1, $var2) {
            $var3 : $var1 + $var2;
            @return $var3;
        }
    

This function can be used in the stylesheet using the normal CSS function syntax as follows,

        div{
            height: add(300, 400) * 1px;
        }
    

As you can see in the above CSS code, we have to specify values for the arguments while calling the function.

We can also set the default value for arguments while defining a function so that if the user doesn't pass any value, the default value of the argument is used.

example 14: @function with arguments

        @function add($var1, $var2: 400) {
            $var3 : $var1 + $var2;
            @return $var3;
        }
    

While calling the function we can pass either one or two parameters. If one parameter is passed then the other argument will take the default value. If both parameters are passed while calling the function then the default value is overridden by the value provided at time of function call.

        div {
            height: add(300) * 1px;
        }
    

While calling a function, we can provide the value for the argument along with the name of the argument as specified in the function definition. So instead of passing the arguments in order or their number, they can be passed by name as well.

example 15: @function with arguments

        div {
            height: add($var2: 300, $var1: 400) * 1px;
        }
    

Sometimes we need to pass different number of parameters to a function in different scenarios. For such usecase we can define our function to take any number of arguments and this could be done the same way as we saw in mixins i.e. when the last argument ends in three dots (ex: $abc...) which is known as the argument list. So when this function is called, all the parameters provided at time of function call are available in the function argument as a list of values, which can then be used in the function.

example 16: @function with arguments

        @function min($numbers...) {
            $min: null;
            @each $number in $numbers {
                @if $min == null or $number < $min {
                    $min: $number;
                }
            }
            @return $min;
        }
        
        .micro {
            width: min(50px, 30px, 100px);
        }
    

@if, @else, @else if

top

SCSS also provides support for flow control by providing @if, @else and @else if at-rules, which can be used in SCSS to write complex code by implementing conditions in stylesheets. While writing SCSS functions or SCSS mixins we can define different style rules depending upon the values of the arguments provided when a mixin is included or a function is called. This can be done using the SCSS @if and @else at-rules, making it easy to write more dynamic style rules.

The @if directive accepts SCSS script expressions and uses the nested styles whenever the result of the expression is anything other than false or null. The @if at-rule can be used to control the execution of a style block based on a condition. The syntax for using the @if at-rule is: @if <expression> {/* statements */}

If the expression evaluates to "true", then the block associated with the @if at-rule is evaluated, compiling into CSS style rules. If the expression evaluates to "false", then the block is skipped.

example 16: @if

        @mixin borderstyle($color, $round: false) {
            border-color: $color;
        }
        @if $round {
            border-radius: 5px;
        }
        .blue-border {
            @include borderstyle(blue, $round: false);
        }
        .red-border-round {
            @include borderstyle(red, $round: true);
        }
    

This will be compiled into following CSS:

        .blue-border {
            border-color: blue;
        }
        .red-border-round {
            border-color: red;
            border-radius: 5px;
        }
    

SCSS @else at-rule is used with the @if at-rule to provide an alternative block which is executed if the @if expression returns false. The @else at-rule is optional and it is not mandatory to use it along with @if at-rule. However, the SCSS @else at-rule cannot be used without an @if at-rule. It should always follow the @if at-rule.The syntax for using the @else at-rule is: @else {/* statements */}

example 16a: @else

        $light-background: #fefefe;
        $light-text: #000000;
        $dark-background: #000000;
        $dark-text: #fefefe;

        @mixin theme-colors($light-theme: true) {
            @if $light-theme {
                background-color: $light-background;
                color: $light-text;
            } @else {
                background-color: $dark-background;
                color: $dark-text;
            }
        }
        .banner {
            @include theme-colors($light-theme: true);
        }
    

This will be compiled into following CSS:

        .banner {
            background-color: #fefefe;
            color: #000000;
        }
    

To define multiple conditional flows, we can use the @else if at-rule along with the @if at-rule. The SCSS @else if at-rule can be used between @if at-rule and @else at-rule to include multiple conditional style blocks.

@else if is used with the @if directive, whenever the @if statement fails then the @else if statements are tried and if they also fails then the @else is executed.The syntax for @else if at-rule is similar to that of @if at-rule: @else if <expression> {/* statements */}

Just like @if at-rule, the @else if at-rule also takes in an expression as a condition, and if the expression of @if at-rule evaluates to false, and the @else if expression evaluates to true, the @else if style block is compiled. Also, the @else if should always be used with the @if at-rule, just like the @else at-rule

example 16b: @else if

        @mixin text-effect($val) {
            @if $val == danger {
                    color: red;
                }
            @else if $val == alert {
                    color: yellow;
                }
            @else if $val == success {
                    color: green;
                }
            @else {
                    color: black;
                }
        }
    

@for

top

The @for rule is used for repeating CSS definitions multiple times in a row. It allows you to generate styles in a loop. The counter variable is used to set the output for each iteration.
The @for directive are of two types: 1/ the @for uses the keyword "through", which specifies the range including both the values of ><start> and ><end>; 2/the @for uses "to" keyword, which specifies the range from <start> value to the value before <end> value.

syntax: @for <variable> from <expression> to <expression> { ... } /* or */ @for <variable> from <expression> through <expression> { ... }

example 17: @for

       - HTML - 
        < p class="paragraph-1">Sassy way< /p>
        < p class="paragraph-2">Sassy way< /p>
        < p class="paragraph-3">Sassy way< /p>
        < p class="paragraph-4">Sassy way< /p>
        < p class="paragraph-5">Sassy way< /p>
        -- SCSS --
        @for $i from 1 to 6 {
          .paragraph-#{$i} {
            font-size: 10px*$i;
          }
        }
    

@each

top

In @each directive, a variable is defined which contains the value of each item in a list.

syntax:@each $var in <list or map></list>

explanation: "$var" represents the name of the variable; @each rule sets $var to each item in the list and outputs the styles using the value of $var. <list or map> are SCSS script expressions, which will return a list or a map.

syntax: @each <variable> in <expression> { ... }

The expression returns a list and the style block is evaluated for each element of the list, which is one by one assigned to the given variable name.

example 18: @each

        - HTML-
        < div class="blue-background">< div>
        < div class="black-background">< /div>
        < div class="yellow-background">< /div>

        - SCSS - using list
        @each $color in blue, black, yellow {
          .#{$color}-background {
              background-color: $color;
            }
        }

        - SCSS - using map
        /* $colors is a map here */
        $colors: (color1: blue, color2: black, color3: yellow);
        @each $key, $value in $colors {
              .#{$color}-background  {
                  background-color: $value;
                }
        }
    

@while

top

SCSS @while is similar to the while loop in any other programming/scripting language. It executes until the specified expression evaluates to true.

syntax: @while <expression>f { ... }

The style block defined with the @while at-rule is evaluated until the expression evaluates to true. We should be careful while using the @while at-rule for looping as this can very easily lead to infinite loops.

example 19: @while

        - HTML -
        < p class="paragraph-1">Sassy way< /p>
        < p class="paragraph-2">Sassy way< /p> 
        < p class="paragraph-3">Sassy way< /p>
        < p class="paragraph-4">Sassy way< /p>
        < p class="paragraph-5">Sassy way< /p>

        - SCSS -
        $x: 1; 
        @while $x < 6 {
            .paragraph-#{$x} {
                font-size: 10px*$x;
            }
        $x: $x + 1;
    }
    

@extend

top

@extend directive is used to share rules and relationships between selectors.

SCSS @extend at-rule allows inheritance of styling rules in your stylesheet. If you wish to define a class in your stylesheet with all the styling rules of another class along with its own specific styling rules, we can use the SCSS @extend at-rule. SCSS @extend at-rule will let you use the CSS properties of one selector in the other.

syntax: @extend <selector></selector>

example 20: @extend

        .message-shared {
            border: 1px solid #ccc
            padding: 10px
            color: #333
        }
    
        .message {
            @extend .message-shared
        }
       .success {
            @extend .message-shared
            border-color: green
        }
        .error {
            @extend .message-shared
            border-color: red
        }
        .warning {
            @extend .message-shared
            border-color: yellow
        }
    

A placeholder selector is defined with its name preceded by a % sign. When we define a placeholder selector, we cannot use this in our HTML but it can only be used for inheritance, which means other selectors can inherit its styling using the @extend at-rule.

example 21: @extend

        %btn {
            border: 1px solid #ccc
            padding: 10px
            color: #333
        }
        .btn-success {
            @extend %btn
            background-color: green
        }
        .btn-error {
            @extend %btn
            background-color: red
        }
    

The compiled CSS code will look like:

        .btn-success {
            border: 1px solid #ccc;
            padding: 10px;
            color: #333;
            background-color: green;
        }
        .btn-error {
            border: 1px solid #ccc;
            padding: 10px;
            color: #333;
            background-color: red;
        }
    

We can even define private placeholder in SCSS by adding a "-" hyphen or an "_" underscore as prefix to the name of the selector. Such placeholder selectors become private and can only be extended by styling classes written within the same stylesheet.

If you use the @extend at-rule to extend any selector and if it doesn't exist in the stylesheet then SCSS will give error. So you should be careful while using the @extend at-rule, because if you change the name of the selector being extended, then it can lead to error. To deal with this, if you want that your stylesheet code doesn't give error, you can use "!optional" at the end of the @extend statement. This will make the inheritance of style rules optional and if the selector being extended is not available, still SCSS will not give error.

SCSS mixins are also used to define reusable style in SCSS just like SCSS extends, so when should we use @mixin at-rule and when should we use @extend at-rule? The answer to this is, when we want to configure the style rules using arguments, in that case we should use SCSS mixins whereas if our requirement is re-using static style rules(just a chunk of style) then in that case we can use the SCSS extends in our stylesheet.


@at-root

top

@at-root directive is a collection of nested rules, which is able to make style block at root of the document.

SCSS @at-root at-rule is not frequently used in SCSS but it helps while implementing advanced nesting with selector functions. We can use this at-rule with any selector(generally the nested selectors defined inside curly braces of another selector) to compile them as root selector in the stylesheet and not as a nested selector. It emits everything within it at the root of the document instead of using normal nesting.

syntax: @at-root <selector> { ... }

We can write the @at-root as @at-root { ... } to have multiple style rules in its scope to put all of them at the root of the document. In fact, @at-root <selector> { ... } is just a shorthand for @at-root { <selector> { ... } }

example 22: @at-root

        div{
            margin: 0px;
            @at-root .column {
                background-color: black;
            }
        }
    

example 22a: @at-root

        div{
            margin: 0px;
           .column{
                background-color: black;
            }
        }
    

@error

top

@error directive displays the SCSS script expression value as fatal error.

SCSS @error is helpful in both mixins and functions. Suppose we need to ensure that the arguments passed in function or mixins are correct, for this we can use @error at-rule to display an error message in case a wrong datatype is provded and stop the compilation of the code.

syntax: @error <expression></expression>

example 23: @error

        mixin setcssfloat($floatvalue) {
            @if $floatvalue !=left or $floatvalue !=right {
                @error "Property #{$property} must be either left or right.";
            }
        }
        $top: top;
        @include setcssfloat($top);
    

@warn

top

@warn directive is used to give cautionary advice about the problem; it displays the SCSS script expression values to the standard error output stream.

SCSS @warn at-rule is used to show warning to a user if the user is sending some incorrect values or maybe some value, which is no longer accepted by the mixin or a function. The @warn at-rule doesn't stop the compilation of the SCSS stylesheet completely.

syntax: @warn <expression></expression>

example 24: @warn

        $known-prefixes: webkit, moz, ms, o;
        @mixin prefix($property, $value, $prefixes) {
            @each $prefix in $prefixes {
                @if not index($known-prefixes, $prefix) {
                @warn "Unknown prefix #{$prefix}.";
                }

                -#{$prefix}-#{$property}: $value;
            }
            #{$property}: $value;
        }
        .tilt {
            // Oops, we typo'd "webkit" as "wekbit"!
            @include prefix(transform, rotate(15deg), wekbit ms);
        }
    

@debug

top

@debug directive detects the errors and displays the SCSS script expression values to the standard error output stream.

In some cases it's useful to check the value of variables while writing SCSS code to debug the code you are writing and to see how it will behave with different input values. SCSS @debug at-rule helps us with this problem.

syntax: @debug <expression></expression>

example 25: @debug

        @mixin div-padding($x, $y) {
            $z : $x + $y;
            padding: $z * 1px;
            @debug "width is: #{$z}";
        }
        
        @include div-padding(100,200);