Codementor Events

Functional SCSS — Well, Kinda

Published Jan 25, 2018
Functional SCSS — Well, Kinda

For me, CSS or SCSS is a means to an end — we need to style elements. However, my pleasure, in terms of the front-end, comes mainly from JS and the puzzles we get to solve creatively.

When I started playing around with loops and conditional statements in SCSS, I was super excited to see that SCSS can also be a fun way to solve styling issues with more traditional programming techniques.

My problem starting out was creating a carrot/triangle pointing to the right. I started to search the net and came across this cool post about using some CSS trickery to create a CSS only arrow.

.arrow-right { 
  width: 0; 
    height: 0; 
    border-top: 20px solid transparent; 
    border-bottom: 20px solid transparent; 
    border-left: 20px solid green;
    }

Okay, great! Now maybe I want to have another arrow pointing down as well. So then, we do this.

.arrow-down { 
  width: 0;
    height: 0;
    border-left: 20px solid transparent; 
    border-right: 20px solid transparent; 
    border-top: 20px solid green;
    }

Also, maybe an arrow left and up just to complete the picture.

.arrow-left { 
  width: 0; 
    height: 0; 
    border-top: 20px solid transparent; 
    border-bottom: 20px solid transparent; 
    border-right: 20px solid green; 
    }
    
.arrow-up {
  width: 0;
    height: 0;
    border-left: 20px solid transparent;
    border-right: 20px solid transparent;
    border-bottom: 20px solid green;
    }

It’s easy to see the pattern here repeating itself. What if I wanted a smaller arrow of, say, 10px?

That would mean creating all of this code over again and just replacing the 20px with a 10px. Moreover, it would violate the DRY principle.

SCSS functions to the rescue!

This is the final code that would be able to generate arrows in all directions and in whatever sizes we choose. For this example: 5px, 10px, and 20px.

$sizes: small 5px, medium 10px, large 20px;
$directions: up right down left;

@mixin carrot($size, $color, $direction) {
  width: 0; 
    height: 0;
    border: $size solid transparent;
    @if $direction == 'down' { border-top: $size solid $color; }
    @if $direction == 'up' { border-bottom: $size solid $color; }
    @if $direction == 'left' { border-right: $size solid $color; }
    @if $direction == 'right' { border-left: $size solid $color; }
} 

@each $size in $sizes { 
  @each $direction in $directions { 
    	.carrot-#{$direction}-#{nth($size, 1)} { 
        	@include carrot(nth($size,2), #fff, $direction); 
        }
    }
}

First, we set up our two variables, $sizes and $directions. Because SCSS doesn’t have the direct concept of arrays, we use what is called a list.

The values are comma separated, and you can think of what is between the commas as the array portion. If we loop over $sizes, we get the first value as [small, 5px] and can access each piece using the nth function.

$sizes: small 5px, medium 10px, large 20px; 
@each $size in $sizes { 
  nth(($size, 1));
}

This would such loop the $sizes list and grab the first term: the small, medium, and large. Lists start with 1 as opposed to 0 with arrays.

The next piece is a @mixin that we will use to create a SCSS function. Inside the @mixin we have four conditionals, which is the only part of the border that changes for each triangle direction. That's pretty much it for the @mixin.

Next, it’s use.

Like we showed above, we will use loops to generate the classes that will define the arrows. More specifically, we will use two loops to create the classes. We first loop over the sizes and then from each size and name, we specify that we create the four directional arrows.

That’s it!

Super simple SCSS functions to abstract repetition. Here is a working example of it. If you click Change View -> Direct Code Links (.css), you can see the CSS that is generated from the code.

Or, click here, for a direct link to the CSS.

Stay Scssy!

Discover and read more posts from Sten Muchow
get started
post commentsBe the first to share your opinion
Show more replies