Gerillass 3.0.0 is out. One gradient mixin replaces two, and text-gradient takes its colours first, so read the migration guide before you upgrade.

Gerillass

v3.0.0

Triangle

Type: Mixin
@include triangle();

* You can call mixins with or without the gls- namespace (e.g. @include gls-triangle();).

The Triangle Sass mixin helps you generate triangles using the ::before or ::after CSS pseudo-elements.

Tip: It works best with text based elements, where it points in a direction to invite the user to take action (for example, dropdown menu labels). It is especially useful when you apply it to the selected element's ::before or ::after pseudo-elements.

Arguments

NameTypeDescription
$directionstringSets the direction of the triangle. Accepts the values top, top-right, right, bottom-right, bottom, bottom-left, left, and top-left. The logical directions inline-start, inline-end, block-start and block-end follow the writing direction instead: inline-end points right on a left-to-right page and left on a right-to-left one.
$colorcolor, keyword, functionThe color of the triangle. Accepts a Sass color, currentColor, a system color such as Canvas, or a function the browser resolves to a color, such as var(), color-mix(), light-dark(), contrast-color() or rgb(from ...). Until 2.3.1 only four functions were accepted, and a system color or contrast-color() was refused, although a border keeps both. inherit, initial, unset and revert are refused, because the color is written into a border-color shorthand beside transparent, where a browser rejects them.
$sizenumber (with unit), functionThe size of the triangle. Multiple values must be separated by a space. Each value can also be var(), env(), or a calculation such as calc() or clamp(). Not a percentage or a negative length, which border-width drops.

When you pass top, right, bottom, left or one of the four logical directions for the $direction argument, you can pass two values to resize the triangle. The first value controls the width of the triangle and the second controls the height.

Examples

Suppose you have an expandable box and you want users to click a label to expand it. Let's apply the mixin to the ::after pseudo-element of the selected element.

HTML
<div class="element">Click here to expand it!</div>
Sass
.element {
  &::after {
    @include triangle;
  }
}
CSS
.element::after {
  content: "";
  height: 0;
  width: 0;
  display: inline-block;
  border-style: solid;
  border-color: black transparent transparent;
  border-width: 8px 5px 0;
}
Result

Now let's change the $color and the $size of the triangle, and separate it from the text by passing a declaration block into the mixin.

Sass
.element {
  &::after {
    @include triangle(
      $color: crimson,
      $size: 6px
    ) {
      margin-left: 6px;
    };
  }
}
CSS
.element::after {
  content: "";
  height: 0;
  width: 0;
  display: inline-block;
  border-style: solid;
  border-color: crimson transparent transparent;
  border-width: 6px 3px 0;
  margin-left: 6px;
}
Result

When you pass one of the top, right, bottom, or left values for the $direction argument, you can pass a second value to resize the triangle. The first value controls the width of the triangle and the second controls the height.

Sass
.element{
  &::after {
    @include triangle(
      $direction: "bottom",
      $color: crimson,
      $size: 10px 6px
    ) {
      position: relative;
      margin-left: 6px;
      top: -2px;
    };
  }
}
CSS
.element::after {
  content: "";
  height: 0;
  width: 0;
  display: inline-block;
  border-style: solid;
  border-color: crimson transparent transparent;
  border-width: 6px 5px 0;
  position: relative;
  margin-left: 6px;
  top: -2px;
}
Result

You can apply the mixin not only to the pseudo-elements, but to the selected element itself.

Sass
.element{
  @include triangle(
    $direction: "top",
    $color: crimson,
    $size: 100px 50px
  )
}
CSS
.element {
  content: "";
  height: 0;
  width: 0;
  display: inline-block;
  border-style: solid;
  border-color: transparent transparent crimson;
  border-width: 0 50px 50px;
}
Result

Logical directions follow the writing direction. inline-end points to where a line ends: right in a left-to-right sentence, left in a right-to-left one, from the same rule. Measured in Chrome 152, each logical direction renders the same borders as its physical twin in both directions.

Sass
.next::after {
  @include triangle("inline-end", currentColor, 8px 12px);
  margin-inline-start: 8px;
}
CSS
.next::after {
  content: "";
  height: 0;
  width: 0;
  display: inline-block;
  border-style: solid;
  border-color: transparent;
  border-inline-start-color: currentColor;
  border-block-width: 6px;
  border-inline-start-width: 8px;
  border-inline-end-width: 0;
  margin-inline-start: 8px;
}
Result

What it refuses

A size the browser drops stops the build. The sizes are written into border-width, which in Chrome 152 drops a percentage and a negative width, so the triangle is not drawn. Until 2.3.1 both compiled; a word or a unitless number was already refused.

Sass
.caret {
  @include triangle("top", red, 5%);
}
Error: `5%` is not a valid $size for `triangle`: a percentage does not work here. A browser drops the border widths, so no triangle is drawn.