Home About Me

Building CSS Triangles and Parallelograms Two Different Ways

A while ago I came across a pagination style that looked especially sharp: angled edges, compact labels, and a shape that felt more dynamic than a plain rectangle. I ended up using the same idea in a blog pagination bar, and the result looked like this:

Screenshot of the pagination style

You can picture the effect as a row of small slanted tags. The interesting part is that this kind of shape can be built in CSS without any images at all. There are two practical approaches: one relies on border, and the other uses transform.

Method 1: Constructing the shape with border

The first technique uses the classic CSS triangle trick. Once you can create a triangle, a parallelogram is just a rectangle joined with two triangles, one on each side.

Why does border produce a triangle in the first place? The basic idea is easiest to understand by looking at how borders behave when an element shrinks down to no intrinsic size:

CSS triangle

There are really only two conditions required:

  1. The element itself must have width: 0 and height: 0.
  2. The unwanted sides need to be hidden by setting their border-color to transparent.

Using the same principle, you can create other shapes too, including trapezoids. Here are the three examples shown above:

#first {
  width: 20px;
  height: 20px;
  border-width: 10px;
  border-style: solid;
  border-color: red green blue brown;
}

#second {
  width: 0;
  height: 0;
  border-width: 10px;
  border-style: solid;
  border-color: red green blue brown;
}

#third {
  width: 0;
  height: 0;
  border-width: 10px;
  border-style: solid;
  border-color: red transparent transparent transparent;
}

Once the triangle itself is clear, the next step is assembling a parallelogram. With the border approach, the shape is made from three pieces:

  • a left triangle
  • a center rectangle
  • a right triangle

Creating three separate elements every time would be cumbersome, so pseudo-elements are a much cleaner option here. :before and :after can be used for the two side triangles, while the main element provides the rectangular middle.

The intended result looks like this:

Three-piece parallelogram

Because the triangles and the center block need to align perfectly, several properties have to stay in sync. This is the kind of CSS that becomes easier to manage in a preprocessor such as Less, Sass, or Stylus. Here is the SCSS version:

//三角形的宽高
$height: 24px;
$width: 12px;

//对平行四边形三部分的颜色进行赋值
@mixin parallelogram-color($color) {
  background: $color;
  &:before { border-color: transparent $color $color transparent; }
  &:after { border-color: $color transparent transparent $color; }
}

//单个三角形的样式
@mixin triangle() {
  content: '';
  display: block;
  width: 0;
  height: 0;
  position: absolute;
  border-style: solid;
  border-width: $height/2 $width/2;
  top: 0;
}

//平行四边形的样式
.para {
  display: inline-block;
  position: relative;
  padding: 0 10px;
  height: $height;
  line-height: $height;
  margin-left: $width;
  color: #fff;

  &:after {
    @include triangle();
    right: -$width;
  }

  &:before {
    @include triangle();
    left: -$width;
  }

  @include parallelogram-color(red);
}

One thing to watch out for: if the slope implied by $height and $width is too steep or too shallow, the edges may render with visible jaggedness. It is worth testing a few size combinations to see which proportions look best in actual browsers.

Method 2: Using transform and skew

The second approach is much simpler conceptually. Instead of piecing together triangles and rectangles, you start with a normal box and skew it into a parallelogram.

That effect can even be used for an outlined shape rather than a filled one, which is something the first method does not handle as naturally. A basic version looks like this:

Outlined parallelogram example

The core of it is transform: skew(...):

<style>
.city {
  display: inline-block;
  padding: 5px 20px;
  border: 1px solid #44a5fc;
  color: #333;
  transform: skew(-20deg);
}
</style>

<div class="city">上海</div>

This does create the parallelogram shape, but it also skews the text inside it:

Skewed Shanghai text

That obviously is not the final result we want. The fix is to wrap the text in an inner element and apply the opposite skew to cancel out the distortion:

Corrected Shanghai label

Here is the full version:

<style>
.city {
  display: inline-block;
  padding: 5px 20px;
  border: 1px solid #44a5fc;
  color: #333;
  transform: skew(-20deg);
}

.city div {
  transform: skew(20deg);
}
</style>

<div class="city">
  <div>上海</div>
</div>

Choosing between the two

Both methods work, but they serve slightly different needs.

The border technique is great when you want to synthesize shapes such as triangles and trapezoid-like tags, then combine them into a filled parallelogram. It is flexible, but it takes more code and can be more finicky to maintain.

The transform method is shorter and easier to understand. For most simple parallelogram labels, it is the more straightforward choice. Its limitation is that it does not help much when you need a shape like the trapezoidal pagination style mentioned earlier.

A rendering issue worth knowing about

There is one practical caveat with border-based triangles: browser rendering can become inconsistent when the page is zoomed.

In testing, white seams could appear in the pagination shape under browser scaling. For example:

  • Safari 8 showed the issue at 150% zoom.
  • Chrome 45 showed it at 125% zoom.

The screenshots below illustrate the problem:

Pagination in Safari at scaled zoom

Pagination in Chrome at scaled zoom

This exposes a real difference in how browsers render Border Triangle shapes under zoom. The behavior is not fully consistent across engines, and no reliable fix was found in this case. Because of that, the pagination bar was eventually rebuilt with the second method using transform instead.