Exploring Unconventional Styling

Single element CSS Shapes

Daniel Fuller
Daniel Fuller Founder & Tech Director, Danimate LLC Family man + CSS enthusiast

Motivation

Whenever I am implementing a new design, I try to build it using a simple and semantic HTML tree. Often designs come with non-content pieces that, at first, seem like it would bloat the markup. Things like custom animated bullet points, connected flow indicators, organic background shapes, or line numbers in a code example.

To maintain a simple HTML tree, most of these items can be delegated to CSS. Though they could be implemented in either the HTML or the CSS, it makes sense to move most of them to the CSS as they are part of the presentation, not the data.

In this post, we’ll explore various shapes and techniques-each using a single HTML element-which can be used to cut down on HTML markup and network requests for icons and simple graphics. Yay for faster page loading!

Base Markup

All the examples will use this pattern:

<div class="shape-SHAPENAME"></div>
or 
<span class="shape-SHAPENAME"></div>
div[class^="shape-"] {
    position: relative;
}
span[class^="shape-"] {
    display: inline-block;
    position: relative;
}

Square

The simplest shape you can make with CSS is a square, since all HTML elements are 2d areas.

.shape-square {
    width: 5rem;
    height: 5rem;
    background-color: #42b171;
}

Rectangle

Rectangles are as simple as adjusting the width or the height of the shape

.shape-rectangle {
    width: 8rem;
    height: 5rem;
    background-color: #42b171;
}

Rounded

Using border-radius you get curved edges as a building block to make a new set of shapes.

.shape-rounded {
  width: 8em;
  height: 8em;
  background-color: #42b171;
  border-radius: 1em;
}

Circle

If you have a square and round the edges until the curves meet, you end up with a circle.

.shape-circle {
  width: 8em;
  height: 8em;
  background-color: #42b171;
  border-radius: 50%;
}

Oval

A rectangle with curved edges can make an oval.

.shape-oval {
  width: 8em;
  height: 5em;
  background-color: #42b171;
  border-radius: 50%;
}

Organic

You can use multiple params to the border-radius property to get interesting results. The order of the params is top-left, top-right, bottom-right, bottom-left, with any undefined properties being implied from the others.

Playing with these values can yield some organic looking shapes.

.shape-organic-1 {
  width: 8em;
  height: 5em;
  background-color: #42b171;
  border-radius: 1em 2em 3em 4em;
}

This uses implied radius for the opposite corners.

.shape-organic-2 {
  width: 8em;
  height: 5em;
  background-color: #42b171;
  border-radius: 2em 6em;
}

Triangle

Another shape technique is to use borders to make shapes. By default, borders are mitered, meaning they form an angle where the two borders meet at the corners. Using this fact, we can make some borders transparent, and some with color to make shapes with angles. This triangle uses a large bottom border on a div with 0 width and 0 height.

To visual this, you can picture the div as a tiny spec at the top of the triangle, with a gigantic border on the bottom. Since the left and right sides also have gigantic borders (but transparent ones) all we see is the bottom border.

.shape-triangle {
  width: 0;
  height: 0;
  border-left: 4em solid transparent;
  border-right: 4em solid transparent;
  border-bottom: 5em solid #42b171;
}

We can control the angles by adjusting the thicknesses of the borders. Having thinner borders on the right and left will make the triangle taller and skinnier.

.shape-triangle-thin {
  width: 0;
  height: 0;
  border-left: 2em solid transparent;
  border-right: 2em solid transparent;
  border-bottom: 5em solid #42b171;
}

Trapezoid

If we adjust the width of the base element, we can get shapes other than triangles.

.shape-trapezoid {
  width: 5em;
  height: 0;
  border-left: 4em solid transparent;
  border-right: 4em solid transparent;
  border-bottom: 5em solid #42b171;
}

Tree

Pseudo elements in CSS are very helpful when you want to add presentation elements that you don’t want in your markup, for instance adding stylish quotation marks before and after a block quote, or line numbers in a code example.

We can (ab)use these pseudo elements, namely :before and :after to add extra shapes to our initial element. Let’s build on that skinny triangle from above.

.shape-tree {
  width: 0;
  height: 0;
  border-left: 3em solid transparent;
  border-right: 3em solid transparent;
  border-bottom: 8em solid #42b171;
  margin-bottom: 5em;

  &:after {
    content: "";
    position: absolute;
    width: 2em;
    height: 2em;
    background-color: brown;
    top: 8em;
    left: -1em;
  }
}

Star

Adding some rotation to the pseudo elements unlocks another set of interesting configurations. This uses three wide triangles carefully rotated and positioned to make the points.

.shape-star {
  margin: 4em 0;
  width: 0;
  height: 0;
  border-left: 5em solid transparent;
  border-right: 5em solid transparent;
  border-top: 3.6em solid #42b171;

  &:after {
    content: "";
    position: absolute;
    width: 0;
    height: 0;
    border-left: 5em solid transparent;
    border-right: 5em solid transparent;
    border-top: 3.6em solid #42b171;
    transform: rotate(-72deg);
    top: -3.8em;
    left: -4.8em;
  }
  &:before {
    content: "";
    position: absolute;
    width: 0;
    height: 0;
    border-left: 5em solid transparent;
    border-right: 5em solid transparent;
    border-top: 3.6em solid #42b171;
    transform-origin: top center;
    transform: rotate(216deg);
    top: -0.7em;
    left: -6em;
  }
}

Heart

A heart can be made with a rotated square and two pseudo element circles.

.shape-heart {
  width: 5em;
  height: 5em;
  background-color: #42b171;
  transform: rotate(45deg);
  margin: 3em;

  &:before {
    content: "";
    position: absolute;
    width: 5em;
    height: 5em;
    background-color: #42b171;
    border-radius: 50%;
    top: -2.5em;
    left: 0;
  }

  &:after {
    content: "";
    position: absolute;
    width: 5em;
    height: 5em;
    background-color: #42b171;
    border-radius: 50%;
    top: 0em;
    left: -2.5em;
  }
}

Cloud

In CSS, we are limited to only two pseudo elements, :before and :after. If we need more shapes than that, we’ll have to resort to using another technique. drop-shadow’s are usually used to add a soft color beneath/around an element. If we use hard edges we can essentially make a copy of that element and position it where we’d like.

Modern browsers also support multiple drop shadows, so we can easily make a cloud using a circle, with a half dozen drop shadows.

box-shadow parameters are x-offset, y-offset, blur, spread and color. Comma separate declarations for multiple and order them from front to back.

.shape-cloud {
  width: 3em;
  height: 3em;
  background-color: #42b171;
  border-radius: 50%;
  margin: 3em 0;
  box-shadow: 3em 0 0 1.4em #42b171, 
              1.2em .8em 0 .3em #42b171, 
              5em -1em 0 .7em #42b171, 
              6em .5em 0 1.1em #42b171, 
              8em -.5em 0 .4em #42b171, 
              9.5em 0 0 0 #42b171;
}

Checkerboard

Using borders, border-radius, pseudo elements :before and :after, and drop-shadows can really make some useful shapes, that are easily animatable and can add life to a website.

Here’s an example using some of the techniques we’ve covered so far.

.shape-checkerboard {
  width: 8em;
  height: 8em;
  background-color: white;
  padding: .1em;
  border: .3em double black;
  margin: 2em 0;

  &:before {
    content: "";
    position: absolute;
    width: 1em;
    height: 1em;
    background-color: black;
    top: .1em;
    left: 1.1em;
    box-shadow: 2em 0 0 black,
                4em 0 0 black,
                6em 0 0 black,

                -1em 1em 0 black,
                1em 1em 0 black,
                3em 1em 0 black,
                5em 1em 0 black,

                0em 2em 0 black,
                2em 2em 0 black,
                4em 2em 0 black,
                6em 2em 0 black,

                -1em 3em 0 black,
                1em 3em 0 black,
                3em 3em 0 black,
                5em 3em 0 black,

                0em 4em 0 black,
                2em 4em 0 black,
                4em 4em 0 black,
                6em 4em 0 black,

                -1em 5em 0 black,
                1em 5em 0 black,
                3em 5em 0 black,
                5em 5em 0 black,

                0em 6em 0 black,
                2em 6em 0 black,
                4em 6em 0 black,
                6em 6em 0 black,

                -1em 7em 0 black,
                1em 7em 0 black,
                3em 7em 0 black,
                5em 7em 0 black
  }
}

And you can add pieces by adding another pseudo element, :after

.shape-checkerboard {
  ...
  &:after {
    content: "";
    position: absolute;
    width: .8em;
    height: .8em;
    background-color: #af2b2b;
    border-radius: 50%;
    top: .2em;
    left: 1.2em;
    box-shadow: 2em 0 0 #af2b2b,
                4em 0 0 #af2b2b,
                6em 0 0 #af2b2b,

                -1em 1em 0 #af2b2b,
                1em 1em 0 #af2b2b,
                3em 1em 0 #af2b2b,
                5em 1em 0 #af2b2b,

                0em 2em 0 #af2b2b,
                2em 2em 0 #af2b2b,
                4em 2em 0 #af2b2b,
                6em 2em 0 #af2b2b,

                -1em 5em 0 #7a7a7a,
                1em 5em 0 #7a7a7a,
                3em 5em 0 #7a7a7a,
                5em 5em 0 #7a7a7a,

                0em 6em 0 #7a7a7a,
                2em 6em 0 #7a7a7a,
                4em 6em 0 #7a7a7a,
                6em 6em 0 #7a7a7a,

                -1em 7em 0 #7a7a7a,
                1em 7em 0 #7a7a7a,
                3em 7em 0 #7a7a7a,
                5em 7em 0 #7a7a7a
  }
}

Animated

Everything we’ve covered so far are animatable properties, except for drop-shadow. If your shape doesn’t use them, then you can animate them!

Here’s a few with hover effects.

.shape-organic-2 {
  ...
  &.hover {
    transition: border-radius 0.2s ease;

    &:hover {
      border-radius: 6em 2em;
    }
  }
}
.shape-trapezoid {
  ...
  &.hover {
    transition: border 0.2s ease;
    margin-top: 2em;

    &:hover {
      border-bottom: 5em solid #af2b2b;
      border-left-width: 2em;
      border-right-width: 6em;
    }
  }
}

Conclusion

There are limitless shape combinations that can be created with CSS using only a single HTML element. Hopefully this sparked some creative ideas!