Guides/ CSS
change_history

CSS Triangle Tutorial: Border Trick & Modern Alternatives

CSS triangles have been a staple of tooltips and speech bubbles for 15+ years. The classic border hack still works, but modern CSS offers cleaner alternatives with clip-path and conic-gradient. This guide covers all three approaches with copy-paste code.

April 2026 · 6 min read

The Classic Border Trick

The oldest trick: a zero-size element with thick borders. Each border is a trapezoid; making three transparent leaves just one triangle.

/* Triangle pointing up */
.triangle-up {
  width: 0;
  height: 0;
  border-left:  20px solid transparent;
  border-right: 20px solid transparent;
  border-bottom: 30px solid #7c5cfc;
}

/* Triangle pointing down */
.triangle-down {
  width: 0;
  height: 0;
  border-left:  20px solid transparent;
  border-right: 20px solid transparent;
  border-top:   30px solid #7c5cfc;
}

/* Triangle pointing right */
.triangle-right {
  width: 0;
  height: 0;
  border-top:    20px solid transparent;
  border-bottom: 20px solid transparent;
  border-left:   30px solid #7c5cfc;
}

/* Triangle pointing left */
.triangle-left {
  width: 0;
  height: 0;
  border-top:    20px solid transparent;
  border-bottom: 20px solid transparent;
  border-right:  30px solid #7c5cfc;
}

Why it works: when an element has width and height of 0, its borders meet at diagonal seams. The non-transparent border you keep becomes a triangle pointing away from itself. Adjust border widths to change triangle proportions — equal left/right = isosceles; unequal = scalene.

Modern Alternative: clip-path

The clip-path approach treats the element as a real box and clips it to a polygon. Code is more intuitive and supports rotation, scaling, and transitions.

.triangle-up {
  width: 40px;
  height: 30px;
  background: #7c5cfc;
  clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}

.triangle-down {
  width: 40px;
  height: 30px;
  background: #7c5cfc;
  clip-path: polygon(0% 0%, 100% 0%, 50% 100%);
}

.triangle-right {
  width: 30px;
  height: 40px;
  background: #7c5cfc;
  clip-path: polygon(0% 0%, 100% 50%, 0% 100%);
}

.triangle-left {
  width: 30px;
  height: 40px;
  background: #7c5cfc;
  clip-path: polygon(100% 0%, 0% 50%, 100% 100%);
}

Advantages of clip-path: (1) the element has real dimensions, so you can apply padding, add content, use flexbox children; (2) easy to animate with transform; (3) readable code — the polygon points are obvious.

Speech Bubble with Triangle Tail

The most common use: adding a tail to a chat bubble or tooltip.

.bubble {
  position: relative;
  background: #7c5cfc;
  color: #fff;
  padding: 12px 16px;
  border-radius: 12px;
  max-width: 300px;
}

.bubble::after {
  content: '';
  position: absolute;
  bottom: -10px;
  left: 20px;
  width: 0;
  height: 0;
  border-left:  10px solid transparent;
  border-right: 10px solid transparent;
  border-top:   10px solid #7c5cfc;
}

Key pattern: use ::before or ::after pseudo-elements so you don't need extra HTML. Match the triangle color to the bubble background color, and position with position: absolute.

Tooltip with Triangle Pointer

.tooltip {
  position: relative;
  display: inline-block;
}

.tooltip:hover::after,
.tooltip:hover::before {
  opacity: 1;
}

.tooltip::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  padding: 6px 10px;
  background: #1a1a1a;
  color: #fff;
  border-radius: 6px;
  font-size: 12px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
}

.tooltip::before {
  content: '';
  position: absolute;
  bottom: calc(100% + 2px);
  left: 50%;
  transform: translateX(-50%);
  border-left:  6px solid transparent;
  border-right: 6px solid transparent;
  border-top:   6px solid #1a1a1a;
  opacity: 0;
  transition: opacity 0.2s;
}

Usage: <button class="tooltip" data-tooltip="Hello world">Hover me</button>

Triangle with Outline / Border

Creating a triangle with a visible outline is where border triangles break down (borders are already used up). Use clip-path or stack two triangles:

.triangle-outlined {
  width: 40px;
  height: 35px;
  background: #1a1a1a; /* outline color */
  clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
  position: relative;
}

.triangle-outlined::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  right: 2px;
  bottom: 0;
  background: #7c5cfc; /* fill color */
  clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}

Comparison: Which Approach When

  • Border trick — best for simple tooltip/bubble tails via pseudo-elements. Maximum browser support. Limitation: can't contain content, can't transition shape smoothly.
  • clip-path — best for modern UIs. Readable code, real dimensions, animatable. Supported in all evergreen browsers since 2018. Use for carousel arrows, ribbon badges, cut-corner cards.
  • SVG triangle — best when you need precise control, stroke, gradients, or interactive behavior. Slightly heavier.
  • Unicode characters (▲ ▼ ◀ ▶) — acceptable for text-like arrows but limited styling.

Frequently Asked Questions

Why use CSS triangles instead of an SVG or image?
Zero HTTP requests, infinitely scalable (with clip-path), inherit color via border-color: currentColor, and trivially themeable via CSS variables. An SVG triangle is fine too, but CSS triangles integrate more naturally with pseudo-elements for speech bubbles.
Can I animate a CSS triangle's size or rotation?
Rotation: yes, via transform: rotate() — works on both border and clip-path triangles. Size animation: smooth only with clip-path (animating transform: scale()) — border triangles can't transition their border-width cleanly.
How do I make the triangle responsive to its parent?
Use clip-path with percentage units — the triangle auto-scales to any width/height. Border triangles use fixed pixel border widths, so they don't scale without JavaScript or CSS variables.
What browsers support clip-path for triangles?
All evergreen browsers since 2018 (Chrome 55+, Firefox 54+, Safari 9.1+). Polygon syntax is universally supported. Only IE11 needs a fallback — and IE is no longer a concern for most sites in 2026.
How do I center a triangle under a button?
For pseudo-element tails: position: absolute; left: 50%; transform: translateX(-50%); on the triangle. For standalone triangles in a flex container: margin: 0 auto or parent justify-content: center.

Free reference

The 47 Tools Cheat Sheet

One printable page with every tool on this site, what it does, and when to reach for it. Free. It asks for an email so Gumroad can send you the file, unlike the tools themselves.