When we make a new component on a website, we’re effectively creating rectangles of different sizes, whether we realise it or not. But what happens if we want to experiment a little? How many different ways are there to make shapes?

In this post I want to roughly outline some of the most common ways to make circles, triangles, and polygons, as well jot down the advantages and disadvantages for these methods so we can experiment with those that might be a little unfamiliar to us.

Here are some of the ways in which you can make a shape on the web:

  1. border-radius
  2. border
  3. rotating shapes with transform
  4. pseudo elements
  5. box-shadow
  6. wrapping text into shapes with shape-outside
  7. clip-path on an element
  8. SVG assets
  9. canvas


The border-radius property is perhaps the easiest way to make a circle, for example:

.element {
  height: 500px;
  width: 500px;
  border-radius: 50%;

See the Pen LVembR by CSS-Tricks (@css-tricks) on CodePen.

You can use any length value for border-radius. Also, if you’re interested, Jessica Eldredge describes why we should use 50% instead of 100% if we’re using a single value to set all four corners at the same time.

Of course, we can also make a number of other shapes with this property, such as rounded rectangles and ovals:

See the Pen 5dd5c582ec9b79c7d8ac38c350bd3f02 by CSS-Tricks (@css-tricks) on CodePen.


  • well supported by modern browsers.
  • only requires a tiny amount of CSS.

Read more about the border-radius property in the Almanac.

Shapes with border

We can make a number of different shapes with the border property. For instance, by setting the backgrounds of three borders of an element to transparent, we can mimic the appearance of a triangle:

.triangle {
  height: 0;
  width: 0;
  border-left: 100px solid red;
  border-right: 100px solid transparent;
  border-bottom: 100px solid transparent;
  border-top: 100px solid transparent;

See the Pen vOpjXZ by CSS-Tricks (@css-tricks) on CodePen.

We can make triangles that point in pretty much any direction that we’d like. Here’s an animated tutorial of how this works:

See the Pen Animation to Explain CSS Triangles by Chris Coyier (@chriscoyier) on CodePen.

If you want to automate this process, there’s the CSS Triangle Generator that will help you out. If you need a more programmatic way to generate CSS triangles in a codebase, we’ve previously written about the CSS Triangle Mixin.

It’s also possible to make trapezoids with this technique:

See the Pen 580955e70863188e57c68338d9dfa2ae by CSS-Tricks (@css-tricks) on CodePen.


  • great browser support.
  • tools are available, for instance the CSS Shapes Generator, to help make these shapes with ease.

Rotating Shapes with transform

To make certain shapes in CSS, such as diamonds, we can use the transform property on a regular square:

.diamond {
  transform: rotate(45deg);

See the Pen a4a12f6351b38e1a41e78676f20f0cf8 by CSS-Tricks (@css-tricks) on CodePen.

In the example above, the diamond is pushed outside of its parent element because of the transform. What we’ll need to do here is use the transform-origin property to realign the diamond:

.diamond {
  transform: rotate(45deg);
  transform-origin: 0 100%;


  • Good browser support.


  • Requires fixing the alignment of the shape with transform-origin, which might be annoying depending on the circumstances.

Pseudo elements

Pseudo elements are very important tools for making shapes in plain CSS as they greatly improve the sheer number of shapes you can make. Let’s take a pentagon, for example:

See the Pen ca0b36c2d7ea75ea7fd5cd982c328006 by CSS-Tricks (@css-tricks) on CodePen.

By using the :before pseudo element, we can make two distinct shapes which we can then position one on top of the other. One of the problems you might notice with the CSS in that example, though, is the finicky values for absolutely positioning these two parts together.

This is my biggest gripe with making complex shapes in CSS: the sheer complexity of the code required. Once you get outside of the realm of pentagons and hexagons you’ll find some gnarly code is required which, on most projects, should be probably be deemed far too fragile.


  • You can make almost any shape with pseudo elements.
  • Doesn’t require an additional HTTP request that an image might.


  • On larger projects, the code required to make certain shapes can become unmaintainable and too complicated to keep around in the long run.


This might be the strangest way to make a shape in CSS, as with the box-shadow property it’s possible to create incredible pixel-art renderings. This demo by Samuel Marchal exploits this technique.


  • Whoa, you can make shapes with box-shadow?


  • It’s probably quite annoying if the image needs to change in the future because editing it requires finding precisely where that pixel value is in the box-shadow property.
  • Image is non-editable by apps like Illustrator, Photoshop, or Sketch.

Wrapping text around shapes with shape-outside

Text can reflow over a shape such as a circle, ellipse or a polygon with the shape-outside property. It’s also important to note that this property will only work on floated elements for now, although this is likely to change in the future. Here’s a simple example:

.element {  
  float: left;
  shape-outside: circle(50%);
  width: 200px;
  height: 200px;

There are many functions to make shapes for text to flow around, such as: circle(), ellipse(), polygon() and inset(). For now let’s just take a closer look at the ellipse() function:

See the Pen 7fa99015d63597648d5e312c5b73ac25 by CSS-Tricks (@css-tricks) on CodePen.

.element {
  shape-outside: ellipse(150px 300px at 50% 50%);

The ellipse() function requires the radii values for the x, y axis of the ellipse, followed by the coordinates to position the center of the shape within its bounding box. For instance, the example above will position the center of the ellipse in the vertical and horizontal center of .element.

However, there is an important gotcha here that we need to identify: when we use shape-outside we’re not influencing the shape of .element in this case. What we’re doing instead is changing the relationship of other elements around it. If we add a border and background to that div we’ll find it’s still rendered as a rectangle:

See the Pen 5e47a80626dfa27a42dd18a0e2b8450b by CSS-Tricks (@css-tricks) on CodePen.

It might be better to think of it this way: with the shape-outside property we’re changing the relationship of other elements around an element, not the geometry of the element itself. To fix that we’ll need to use shape-outside alongside the clip-path() property, such as in this example:

See the Pen 4e5420d8c1a2766b25dd3c98f684bf9c by CSS-Tricks (@css-tricks) on CodePen.

There’s a lot more to the shape-outside property, so it’s a good idea to check out the Almanac entry.


  • Permits the dynamic reflow of text, which might be important for responsive interfaces.
  • Can set the bounding box to margin, padding and border. This gives us fine control over the position of these relationships.


  • Isn’t supported by IE or Firefox.
  • Does’t change the actual shape of the element.


As we saw in the previous example with shape-outside, we can use similar functions with clip-path including inset(), polygon(), and ellipse(). Here’s an example:

.element {
  width: 200px;
  height: 200px;
  clip-path: polygon(0% 100%, 100% 100%, 0% 0%);

See the Pen 84ce4f54c0d96b1ba0a2e9a9290876fb by CSS-Tricks (@css-tricks) on CodePen.

The comma-separated list defines the coordinates for each point in the shape so the first two values, 0 100%, add a point in the bottom left hand corner of our div. Next, we add a point to the bottom right of the shape and add the last point to the top left of the element. Although this is merely a simple triangle, this example shows the sort of power developers can have over shapes with this new property.

Also, it’s worth noting that the clip-path property is entirely animatable, so long as you have the same number of conditions passed into the function:

See the Pen 10c03204463e92a72a6756678e6348d1 by CSS-Tricks (@css-tricks) on CodePen.

If these functions seem a little confusing, it’s probably best to experiment with a tool like Clippy to help you figure out the syntax:

For more information, check out the Almanac entry for clip-path and Clipping and Masking in CSS.


  • We can make complex shapes without the need for requesting another asset like an image.


  • If you want text to wrap around the shape, you’ll need to use clip-path in conjunction with the shape-outside property.


You can draw literally anything your heart desires with Scalable Vector Graphics, from consoles and logos to icon systems and social media buttons.

It’s sort of outside the scope of this post to go into that much detail about how to use SVG because there are so many best practices and techniques to mention. But generally, if there’s a shape that’s required for a project, my default choice is to use an SVG because it means less wacky, unpredictable code which will certainly be required for the more complicated shapes. It also means that designers can readily edit the shapes if they require touching up.

If you’d like to learn more about SVG then check our compendium of SVG information.


  • Small file sizes (if you optimise them).
  • You can draw them in any popular graphics editor.
  • People unfamiliar with CSS or JavaScript can make them quite easily.
  • They can scale to almost any size without blurring.
  • Wide browser support and plenty of available fallbacks.
  • You can add them into the markup and make them accessible to screen readers.
  • Animatable with CSS and JS.


  • If they’re very simple shapes then you can probably get away with using a pure CSS method instead.


The canvas element is particularly useful for graphs or making interactive games, as it was initially designed to draw graphics with JavaScript. Unfortunately, a tutorial on canvas is outside the scope of this post, but it’s useful to understand what it can be used for. This is how we might draw a square with canvas:

var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#0074d9';
ctx.fillRect(0, 0, 100, 100);

See the Pen 194842e7086d6b740ba102fd3be9c510 by CSS-Tricks (@css-tricks) on CodePen.

For every canvas we need to pass the "2d" string into the .getContext() function. There’s not a 3d context yet, but that might be implemented in the future.

MDN has a great canvas tutorial that’s worth exploring if you’re interested in how to manipulate shapes with JavaScript.


  • Great for making games and interactive charts.


  • Requires JavaScript as a dependency.

Wrapping up

Making shapes in web design is much like picking which vertical alignment technique is best: there is no perfect technique, it all depends upon your requirements. So, in a lot of projects I’ve worked on lately, I haven't picked just one technique but a sprinkling of nearly all of them. As long as everything is documented and you’re not trying to confuse other developers, these tricks can compliment one another to solve any problem when working with shapes.

More Info and Resources