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:
border-radius
border
- rotating shapes with
transform
pseudo elements
box-shadow
- wrapping text into shapes with
shape-outside
clip-path
on an element- SVG assets
canvas
border-radius
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.
Advantages:
- well supported by modern browsers.
- only requires a tiny amount of CSS.
Read more about the border-radius
property in the Almanac.
border
Shapes with 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.
Advantages
- great browser support.
- tools are available, for instance the CSS Shapes Generator, to help make these shapes with ease.
transform
Rotating Shapes with 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%;
}
Advantages
- Good browser support.
Disadvantages
- 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.
Advantages
- You can make almost any shape with pseudo elements.
- Doesn’t require an additional HTTP request that an image might.
Disadvantages
- On larger projects, the code required to make certain shapes can become unmaintainable and too complicated to keep around in the long run.
box-shadow
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.
Advantages
- Whoa, you can make shapes with
box-shadow
?
Disadvantages
- 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.
shape-outside
Wrapping text around shapes with 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.
Advantages:
- 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.
Disadvantages:
- Isn’t supported by IE or Firefox.
- Does’t change the actual shape of the element.
clip-path
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.
Advantages
- We can make complex shapes without the need for requesting another asset like an image.
Disadvantages
- If you want text to wrap around the shape, you’ll need to use
clip-path
in conjunction with theshape-outside
property.
SVG
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.
Advantages
- 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.
Disadvantages
- If they’re very simple shapes then you can probably get away with using a pure CSS method instead.
canvas
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.
Advantages
- Great for making games and interactive charts.
Disadvantages
- 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
- Almanac entry for
clip-path
- More info about
clip-path
- W3C on CSS Shapes
- The Shapes of CSS
- Getting started with CSS Shapes
- Clippy
- Adobe’s CSS Shapes CodePen collection
- Clipping and masking in CSS
- Border-radius: 50% vs 100%
- How to get started with CSS shapes
- Shapes editor Chrome extension
- Canvas tutorial on MDN
- A compendium of SVG information
Great post Chris. Really cool technique with the box-shadow.
This isn’t CHris. Chris got some new writers
I’d agree that making shapes with CSS is far too difficult. However, as SVG becomes the norm, this should become less of a problem. Still, it can be quite helpful to understand how shapes in CSS work. Thanks for the fantastic post!
Great resource! Thanks Robin.
That’s exactly what WebGL is: a 3D context for canvas, accessed through
.getContext("webgl")
.There’s a tonne of things you can do with stacked background gradients too. I made this little mixin to emulate the corners shapes we don’t have yet.
The bevel one is easy for an octagon for example, or the scoop for a sort of four point rounded star shape.
This is the best way to create shapes , thank you for introducing this web.
Nice resoureces site
Decent article. Just like a lot of stuff in Front End Development at the moment, there is no clean cut ‘right choice’ for shape creation. SVG still seems to be the widest supported and most flexible one as yet though. That said, it’s obviously overkill for simple shapes.
For
shape-outside
, listing “Does’t change the actual shape of the element.” as a disadvantage is misguided. The property itself isn’t meant to do that that as its name implies. What it does change on the (floated) element is the shape of the float area which influences layout, not graphics.@Matthewe3man I’d argue that there is a “right choice” for shape creation. If it’s graphical in nature, then SVG is the correct solution. CSS itself is very permissive, therefore we can bend
box-shadow
, transforms and other properties to create the illusion of shapes. But that often yields complex code which is fragile and difficult to maintain and debug.SVG may be embedded or referenced as an image. In very well considered situations making that extra HTTP request for an image is preferable than mixing in convoluted CSS in a blind pursuit of performance.
When using
shape-outside
property, one should addpointer-events:none
together with it, this way the user can again select the clipped text, even when clicking over the element.