HTML & CSS
Article

Sass Basics: Control Directives and Expressions

By Reggie Dawson

If you have used Sass for while or looked at the code of a framework like Foundation, you will notice a lot of advanced features used in mixins. These mixins use control directives such as @if and @for to accomplish things like setting up classes for grid systems.

Continuing with the basics of Sass we will discuss these control directives and see how you can use them in your projects. You may not ever find a need to use these control directives but its always good to know what tools are at your disposal.

if()

This is a little different in that it is not a control directive but a built in function in Sass. Not the same as the @if directive, if() allows you to test for a condition and return one of two possible values. The condition we test for is either true or false. For example:

@mixin test($condition) {
    $color: if($condition, blue, red);
    color:$color
}

.firstClass {
    @include test(true);
}

.secondClass {
    @include test(false);
}

This compiles to:

.firstClass {
    color: blue;
}

.secondClass {
    color: red;
}

The if() function arguments are the condition to test, true result, and false result Any value other than false or null is considered true. In the example above we can substitute a number for true and get the same result.

.firstClass {
    @include test(1);
}

@if

The @if directive takes an expression and returns styles if it results in anything other than false or null. For example:

@mixin txt($weight) {
    color: white;
    @if $weight == bold { font-weight: bold;}
}

.txt1 {
    @include txt(none);
}

.txt2 {
    @include txt(bold);
}

Which gives us:

.txt1 {
    color: white;
}

.txt2 {
    color: white;
    font-weight: bold;
}

We can expand on the @if directive with multiple @else if statements and one final @else. This way we can test for multiple conditions. We can expand on the last example like this.

@mixin txt($weight) {
    color: white;
    @if $weight == bold { font-weight: bold;}
    @else if $weight == light { font-weight: 100;}
    @else if $weight == heavy { font-weight: 900;}
    @else { font-weight: normal;}
    }

.txt1 {
    @include txt(bold);
}

.txt2 {
    @include txt(light);
}

.txt3 {
    @include txt(heavy);
}

.txt4 {
 @include txt(none);
}

.txt5 {
    @include txt(normal)
}

This in turn gives us

.txt1 {
    color: white;
    font-weight: bold;
}

.txt2 {
    color: white;
    font-weight: 100;
}

.txt3 {
    color: white;
    font-weight: 900;
}

.txt4 {
    color: white;
    font-weight: normal;
}

.txt5 {
    color: white;
    font-weight: normal;
}

I have included the last two classes to demonstrate how the addition of @else changes how the @if directive works. In the first example without using bold as the argument it would not give us a font-weight. When you add @else, any argument that doesn’t match the other @if or @else if’s will get the styles of the @else statement. That’s why .txt4 and .txt5 have the same font-weight.

@for

The @for directive lets you output styles in a loop. The directive can be used either as a start through end or start to end. The difference is that start through end includes the ending number while start to end does not include the end number. The @for statement uses a variable to track the loop against the ranges. If we want to count down instead of up we would make our start number larger than our end number. Lets look at how we setup the @for statement.

@for $i from 1 through 12 {
    .col-#{$i} { width: 100/12 * $i;}
}

Here is a @for statement we could use to setup columns for a grid system. The @for is followed by the variable, in this case $i. We then follow that with from and our starting (1) through ending (12) number. On each repetition of the loop we generate a style. Notice how we use interpolation to use the variable as part of the classes we generate.

.col-1 {
    width: 8.33333;
}


.col-2 {
    width: 16.66667;
}


.col-3 {
    width: 25;
}


.col-4 {
    width: 33.33333;
}

I didn’t include all of the styles generated by the @for, as they go all the way up to 12. As you can see on each pass of the loop a style was created with the value of the variable added to the class name. We also did a calculation based on the variable to generate the proper width.

@each

The @each directive uses a list or map instead of starting and ending values. On each pass of the loop the variable gets assigned a value from the list or map.

@each $usr in bob, john, bill, mike {
    .#{$usr}-avatar {
        background-image: url('/img/#{$usr}.png');
     }
}

The @each directive is followed by our variable, $usr. After that we have our list that will be assigned to the $usr variable. We also could have used a map as our argument. After that we use interpolation to build our class as well as displaying the correct picture.

.bob-avatar {
    background-image: url("/img/bob.png");
}

.john-avatar {
    background-image: url("/img/john.png");
}

.bill-avatar {
    background-image: url("/img/bill.png");
}

.mike-avatar {
    background-image: url("/img/mike.png");
}

If we were going to use a map we have to change our @each statement and use multiple assignment. We can use a map in the @each statement like this.

$ppl: ( usr1:bob, usr2:john, usr3:bill, usr4:mike );

@each $key, $usr in $ppl  {
    .#{$usr}-avatar {
        background-image: url('/img/#{$usr}.png');
    }
}

We have to add a second variable to hold the key of each value. If we didn’t, instead of getting the same result as the last example, our keys and values will be in the styles we generate. We can also use multiple assignments on lists.

$alt: alert, yellow, red;

$sub: submit, white, green;

$bck: back, blue, transparent;

@each $type, $txt, $back in $alt,$sub,$bck {
    .#{$type}-button {
        color: $txt;
        background-color: $back;
    }
}

Here we are taking multiple lists and using them to build our classes. As we make a pass over each list the items in the list are assigned to the variables in the @each statement. This gives us:

.alert-button {
    color: yellow;
    background-color: red;
}

.submit-button {
    color: white;
    background-color: green;
}

.back-button {
    color: blue;
    background-color: transparent;
}

@while

The @while directive outputs styles until the statement is false. Similar to the @for directive, the @while directive allows us more flexibility in our loops. I can rewrite the @for directive from above as a @while loop.

$x:1;

@while $x < 13 {
    .col-#{$x} { width: 100/12 * $x;}
    $x: $x + 1;
};

Instead of setting our range inside of our statement like the @for directive, we set a value in our variable. Then we use that value as our test against the @while statement. In this case we said that as long as $x is less than 13, output styles. Once we reach 13 the statement will be false and the loop will stop. The key thing to remember is to increment your variable or your loop will never end. As you can see the example is adding 1 to our variable until it reaches 13.

Conclusion

Sass really includes a lot of powerful features that make our front-end development easier. Although the control directives are powerful, unless you are building a large framework you may not find a lot of uses for them. Like I said before the important thing is to know the tools available to you. Maybe one day you will find a use for one of these control directives.

Free Guide:

7 Habits of Successful CTOs

"What makes a great CTO?" Engineering skills? Business savvy? An innate tendency to channel a mythical creature (ahem, unicorn)? All of the above? Discover the top traits of the most successful CTOs in this free guide.

Recommended
Sponsors
Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in Front-end, once a week, for free.