Search

Shapes

This guide for shapes in CSS comes from an article published by Alvaro Montoro in Level Up Coding.

Rectangle

Initially, everything is a rectangle in HTML. So, a rectangle is simple to draw; specify a width and a height. If that doesn’t work, you may use an element with an inline display, switch to a block or inline-block element, and you should be fine.

Square

A square is a rectangle where the width and the height have the same value. We could take the rectangle code and change the height to have the same value as the width.

And that would work, but… If we want to change the size of our square, we’ll need to update two values each time. It’s not a big problem, but in CSS, we have the aspect-ratio property that allows us to specify the relation between width and height. Setting a value of 1 or 1/1 will also result in a square with the same lines of code, but now we only need to update one line of code to resize it:

Circle

Starting from a square, we need to set a rounded shape. We achieve that by using border-radius and assigning it to a considerable percentage value (50% or higher will do).

Ellipse

An ellipse is a rounded shape like a circle, but instead of a square, it’s based on a rectangle. (There’s a more accurate and technical definition of an ellipse, but I’ll settle for this one for now.) So we’ll add the border-radius property like in the circle, but to a rectangle instead of a square.

Oval/Ovoid

An oval and an ellipse are not the same. There are some technical definitions of interior circles crossing each other or not, but for simplicity, we’ll consider that an oval resembles an egg. We achieve this shape by using both values of the border-radius property. Yes, there are two sets of up to 4 values each: horizontal radii then vertical radii separated by a forward slash (/).

We’ll set the horizontal radii to 100%, then specify larger vertical radii values for the top corners and smaller values for the bottom corners. Something like this:

Bell

A bell is an exaggerated ovoid, where one side is long and rounded, and the other is flat (although still with a soft curve). To obtain this shape, take an oval and make the large values larger and the small values smaller.

If you create CSS Art, this shape can be convenient for bodies and even faces (adjusting the radii values slightly).

Arch

A slight variation of the ellipsis and bell, an arch is flat at the bottom and curved at the top. There’s no playing with the values for this one; we can just set the border-radius property to a fixed value

Eye

The first shape of the three that require a slight rotation. We’ll start from a square and then set the border radius for two opposite corners while leaving the other two corners at zero. I always start from the top left corner and add a 45-degree rotation, but you could pick any other corner and adjust the rotation accordingly.

You can use the rotate: 45deg property or also transform: rotate(45deg). Either way will work. As for the border-radius, the higher the value, the softer the eye curvature will be (duplicate values to allow one side to be taller than the other: 80% 0 100% 0.)

Tear

the tear shape is a variation of the eye shape. Same code, just changing the border-radius: max out three of the radii to get a circular shape and leave the last corner radius to zero so it ends in a point.

Heart

Drawing a heart is slightly different from the previous shapes, as it will use the element and both ::before and ::after pseudo-elements. We start from a square, rotate it 45 degrees, and then add the pseudo-elements as circles (see above). We translate one pseudo horizontally and the other vertically (which will look diagonally for both as the element is rotated), and it’s done. The code may seem “complicated,” but the idea is simple.

Triangle

Many online articles discuss how to draw a triangle using borders, a height/width of zero, and some transparent colors. I would highly discourage that approach. While it works, it is old-fashioned and can be a hassle if we want flexibility and responsiveness.

Instead, I recommend using clip-path for drawing a triangle –and some of the following polygonal shapes. With clip-path, we specify a path (it can be using polygons, an image, an actual path, etc.) that defines a shape. Everything outside of that shape will be clipped. In the case of a triangle, we only need 3 points.

Trapezoid

Another polygon. Which are simple to make using the polygon() function in clip-path. In this case, we’ll start from a rectangle or a square, and we’ll need four points: the bottom ones will be in the corners, and the top will be slightly inside. And we are done

Octagon

The good news is that the clip-path/polygon() method can be extrapolated to any polygonal shape.

Spark

A spark is an octagon variation. The only difference is where four of the points will be located. While in the octagon, they are towards the outside; in the spark, they will be towards the inside (imagine a rotated square).

Moon

The moon can take many forms. By a moon shape, we mean a crescent (or decrescent). We can quickly achieve this by starting with the circular shape and applying a box-shadow. Box shadows allow five values: horizontal translation, vertical translation, fuzziness (optional), scale (optional), and color (optional, text color by default). Depending on whether we want a crescent or a decrescent, we’ll add a big shadow to the right or left.

    .moon {
        width: 300px;
        aspect-ratio: 1;
        background-black;
        border-radius: 50%;
        box-shadow: -90px 0 0 80px black;
    }

As an alternative implementation, I recommend using masks instead of shadows. This is because with the mask implementation, the drawing of the moon is clearly defined within the flow of the page, as it matches the size of the element used to draw it (we could use inset shadows to avoid this problem). Plus, masks provide more flexibility than shadows.