Add Conditional Logic To Sass With Control Directives

One of the ways CSS can be limiting is the lack of conditional logic and loops. You’re limited in your ability to set a style if one condition is true or while another remains true. There are media queries which offer some conditional logic, but odds are you’ve wished you could test against more conditions than media queries allow.

Remote Control

One of the reasons people choose preprocessors like Sass is because they offer conditional logic and looping mechanisms as control structures.

I’m getting close to the end of this series on Sass data types, operators, and functions having already covered the data types Sass supports such as, numbers, strings, colors twice, lists also twice, and finally maps. We’re heading toward custom functions, but we have one more topic to get to first, control directives.

Control Directives in Sass

If you’ve done any programming and are familiar with control structures you can probably skim through this post and next week’s to get the Sass syntax and maybe pick up a few other things along the way.

If you haven’t written any programs before, a control structure is a way to control the flow of your program. The control structure is a block of code that runs if a certain condition applies or it continues to run until some condition is or isn’t met.

For example imagine you’re driving and you come to a traffic light. You do different things at the light based on which of the lights is currently lit.

  • If the light is red, you stop.
  • If the light is green, you go.
  • If the light is yellow, you speed up and look around to see if any cops saw you speed through the intersection before the light changed to red. Or you do what you’re supposed to do and slow down because the light is about to change to red.

The idea is you do different things based on the conditions when you approach the light. A control structure is the way you code the conditions and logic. You won’t use control directives all the time, but they’re valuable when writing mixins and custom functions.

Sass provides a handful of control directives. I’ll cover @if and @for today and then talk about @each and @while next week.

The @if Directive

The first directive we’ll talk about is @if, which takes an expression, evaluates it as true or false, and based on the evaluation runs or doesn’t run some code. It allows you to create different branches in your code that run under different conditions.

1
2
3
4
5
6
7
8
9
h1 {  
  @if 4 + 5 == 9 {  
    font-size: 2em;  
}

  @if 22 < 11 {  
    font-family: Myriad Pro;  
  }
}

The Sass compiles to:

1
2
3
h1 {  
 font-size: 2em  
}

Since 4 + 5 is equal to 9, the first block of code setting the font-size to 2em runs. Since 22 isn’t less than 11, the second block of code doesn’t run. In both cases the expression is evaluated and if it’s true the code runs and if it’s false, the code doesn’t run.

The @if directive is more practical when combined with @else as in if this expression is true run this code, else if this next expression is true run the following block of code and so on until the last statement, which is usually a catchall for every remaining possibility.

Here’s an example where I change the color of an h1 based on the color of the body background.

1
2
3
4
5
6
7
8
9
10
11
12
13
$body: blue;

h1 {  
  @if $body == red {  
    color: cyan;  
  } @else if $body == green {  
    color: magenta;  
  } @else if $body == blue {  
    color: yellow;  
  } @else {  
    color: black;  
  }
}

Ignoring how awful these color combinations would probably look, the code compiles to the following.

1
2
3
h1 {  
  color: yellow;  
}

Because $body was blue in the example, the expression testing for red failed and the code to set the color as cyan didn’t run. Next the the expression to test for green failed. Then the test for blue returned true and the color was set to yellow. The “program” then exits the block of code.

The if() Function

There’s also a built-in if() function that allows you to specify what happens if the expression evaluates to true or false. It takes three arguments, the first is the condition to test, the second is what to return if the condition evaluates to true, and the third is what to return if the condition evaluates to false.

1
2
3
4
5
6
$condition: false;

h1 {  
  $color: if($condition, blue, red);  
  color: $color;  
}

Since $condition is false, the function returns the second of the two possible outcomes, which is red and the Sass compiles to:

1
2
3
h1 {  
  color: red;  
}

The difference between the @if directive and the if() function is the @if directive will evaluate the expression and either run or not run code based on the result of the evaluation, while the if() function will evaluate an expression and then return one of two options based on the results of the evaluation.

  • @if — evaluates expression and runs code
  • if() — evaluates expression and returns a value

The @for Directive

The @for directive sets a counter and loops through a block of code as long as the counter falls within the specified bounds you set.

1
2
3
@for <$variable> from <start> through <end> {  
 code to run goes here  
}

The first time through the @for loop, the value of $variable will be <start>. The next time through the loop the value will be <start> + 1. The time after it will be <start> + 2 and so on until such a time when the value of $variable equals <end> in which case your code will run one last time and then move on to whatever code follows the loop.

There are actually two forms of the @for directive, with the previous code being one. Here’s the other.

1
2
3
@for <$variable> from <start> to <end> {  
 code to run goes here  
}

There’s not a lot of difference between them. In fact the only difference is the use of to as opposed to through , but there’s a significant difference between them. When “through” is used, the loop runs one more time when <$variable> = . When “to” is used it doesn’t.

How about a more practical example?

Here I’ve set up the @for directive to run from 1 through 8. The first time through the loop the variable $i will equal 1. When the code inside the loop runs, the value will be increased to 2 and the code will run again. It will continue to run through the loop where $i = 8 and then once $i is increased to 9, the condition in the directive will no longer be true and the code inside the loop no longer runs.

1
2
3
4
5
@for $i from 1 through 8 {  
 $width: percentage($i/8);

 .col-#{$i} { width: $width; }  
}

The code inside the loop takes the value of $i, divides it by 8, and uses the percentage function (one of the number functions) to turn the result into a percentage and set that percentage on the variable $width. 1/8 becomes 12.5%. 2/8 becomes 25% and so on until the last time through the loop when 8/8 becomes 100%.

The code also uses interpolation to add the value of $i to the class name and then set the width of that class equal to whatever is in the variable $width that time through the loop.

The code compiles to the following.

1
2
3
4
5
6
7
8
.col-1 { width: 12.5%; }  
.col-2 { width: 25%; }  
.col-3 { width: 37.5%; }  
.col-4 { width: 50%; }  
.col-5 { width: 62.5%; }  
.col-6 { width: 75%; }  
.col-7 { width: 87.5%; }  
.col-8 { width: 100%; }

This site currently uses similar classes to create an 8-column grid, though at the time I wasn’t using Sass and had to write out each class. The nice thing about the @for loop is if you change your mind and want 12 columns instead of 8 all you have to do is change the <end> value from 8 to 12 and you’ll have CSS for .col–9, .col–10, etc. with the correct widths inside.

I said above that the counter will increment by one each time through the loop. That’s only true if <end> is greater than <start>. If the reverse is true and <start> is greater than <end>, the counter will decrement from <start> to <start> – 1, and then <start> – 2 and so on.

Here’s how the last example would look rewritten to decrease the counter instead of increase it.

1
2
3
4
5
@for $i from 8 through 1 {  
 $width: percentage($i/8);

 .col-#{$i} { width: $width; }  
}

which compiles to:

1
2
3
4
5
6
7
8
.col-8 { width: 100%; }  
.col-7 { width: 87.5%; }  
.col-6 { width: 75%; }  
.col-5 { width: 62.5%; }  
.col-4 { width: 50%; }  
.col-3 { width: 37.5%; }  
.col-2 { width: 25%; }  
.col-1 { width: 12.5%; }

Closing Thoughts

Control directives allow you to add conditional logic to your Sass code. You can branch your code or loop through your code until certain conditions are true or no longer true.

Hopefully the simple examples here have given you some ideas how you might use control directives in your own code. Next week I’ll finish up the talk about the remaining control directives, @each and @while, and the week after I’ll close out the series showing how to write your own functions.

Download a free sample from my book, Design Fundamentals.

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *