# More elegant Sass @mixin to create pseudo-element shapes

I picked up Sass last week, and I'm already diving into expressions. I have a @mixin that creates a CSS border triangle using the following call: .foo:after { ... @include triangle(bottom,8px,7px,8px,#4986c8); } producing something like:

Here's my @mixin:

@mixin triangle($dir,$tl,$size,$br,$clr) {$a: solid transparent;
@if $dir == top { border-left:$tl $a; border-bottom:$size solid $clr; border-right:$br $a; border-top: 0; } @else if$dir == right {
border-top: $tl$a; border-left: $size solid$clr; border-bottom: $br$a; border-right: 0;
} @else if $dir == bottom { border-left:$tl $a; border-top:$size solid $clr; border-right:$br $a; border-bottom: 0; } @else if$dir == left {
border-top: $tl$a; border-right: $size solid$clr; border-bottom: $br$a; border-left: 0;
}
}


Works as expected; this just doesn't seem the most elegant way to write this particular mixin. How might you do this, or any improvement tips for my code?

In the same vein, I also created this (hopefully it is self-explanitory) to be used alongside:

@mixin pseudo-pos($dir) { content: ""; position: absolute; @if$dir == top { bottom: 100%; }
@else if $dir == right { left: 100%; } @else if$dir == bottom { top: 100%; }
@else if $dir == left { right: 100%; } }  ## 1 Answer # Refactoring You can DRY this up a bit by taking advantage of lists and the zip function. @mixin triangle($dir, $color,$size, $leg1:$size, $leg2:$leg1) {
$sides: 0,$leg1 solid transparent,
$size solid$color,
$leg2 solid transparent;$order:
( top: top right bottom left
, right: right bottom left top
, bottom: bottom right top left
, left: left bottom right top);

$x: zip(map-get($order, $dir),$sides);

border: {
@each $p,$s in $x { #{$p}: $s; } } }  # Misc. Avoid using abbreviated variable names like $clr. It might seem obvious to you that it's short for color, but I have a product sitting under my sink called CLR. I had to read the mixin's code in order for me to discern what it was supposed to be for.

I've modified the argument order here and added some defaults so that you only have to give 1 piece of size information if you want an equilateral triangle, 2 pieces will give you an isosceles. You probably don't really need that last argument, but I threw it in anyway.

# Improving further

I don't have time at the moment to go into this, but things could further be improved by doing the following:

• Specifying height/width rather than the desired border width
• Using shorthand

You can see what I mean by looking over the results from a CSS triangle generator

• Wow, that's a lot of new things. I knew there was some way I could use lists but just didn't know how. "leg" is exactly the name I was looking for... I've long forgotten my trig terms. I love the (..$leg2:$leg1) to shorten calls - great idea. Thanks for DRYing that out for me! I'ma try that now. – Phil Tune Feb 10 '15 at 18:50
• Hi @philtune! If you liked this and it helped you, how about upvote + accept to reward the answer? – janos Feb 15 '15 at 11:47