CSS Triangle Mixin

Kitty Giraudel on

There is a fairly popular CSS hack using transparent borders on a 0-width / 0-height element to mimic triangles. There is a CSS snippet here on CSS-Tricks that depicts it.

If, like me, you never quite remember how it works, be sure we can use Sass to help us.

/// Triangle helper mixin /// @param {Direction} $direction - Triangle direction, either `top`, `right`, `bottom` or `left` /// @param {Color} $color [currentcolor] - Triangle color /// @param {Length} $size [1em] - Triangle size @mixin triangle($direction, $color: currentcolor, $size: 1em) { @if not index(top right bottom left, $direction) { @error "Direction must be either `top`, `right`, `bottom` or `left`."; } width: 0; height: 0; content: ''; z-index: 2; border-#{opposite-position($direction)}: ($size * 1.5) solid $color; $perpendicular-borders: $size solid transparent; @if $direction == top or $direction == bottom { border-left: $perpendicular-borders; border-right: $perpendicular-borders; } @else if $direction == right or $direction == left { border-bottom: $perpendicular-borders; border-top: $perpendicular-borders; } }

Additional notes:

* The opposite-position function comes from Compass; if you do not use Compass, you might need to have your own;
* The mixin does not deal with positioning the triangle; it is perfectly fine to combine it with a positioning mixin though;
* The content directive is meant to allow it to be used on pseudo-elements, which actually ends up being most cases.

Usage

.foo::before { @include triangle(bottom); position: absolute; left: 50%; bottom: 100%; }
.foo::before { width: 0; height: 0; content: ''; z-index: 2; border-top: 1.5em solid currentColor; border-left: 1em solid transparent; border-right: 1em solid transparent; position: absolute; left: 50%; bottom: 100%; }