Interactive, accessible circle wedges with only CSS
Tags: css, javascript, tutorial
Published: 2020-10-19 13:52:49

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ww0n075kh4k0dd2q4m0q.png)

It's one of those things you're almost never asked as a front end dev - but when you are, it's a struggle to find a working example on the web.

I've searched everywhere, and found many solutions - all of which are very superficial, in other words they fill the design aspects but don't give you any usable or accessible elements in the end.

##The request:

The client says, "Hey, what we really want here is a spinny wheely thing - like the one at carnivals where you can win a prize depending on where you land - but instead of spinning it, we want each wedge to represent [insert anything you like here] - is that possible? 

And you say "Sure..." because it can't be *that* hard, right?

And then you suffer. All the solutions out there don't create clickable, accessible, style-able elements. 

##The solution:
[tl;dr] [Codepen](https://codepen.io/tjbauwens/pen/bGepqoj)

In it's simplest form you create a container, and make sure it's overflow is hidden and that it's a perfect circle with `border-radius: 50%`

In the markup you can add the inner elements - they can be buttons, divs, a ul/ol with lis etc... It doesn't really matter what you put in there, it's the CSS calculations that count. Here's my example HTML"

```html
<div class="pie">
  <button>
    <span class="text">1</span>    
  </button>
  <button>
    <span class="text">2</span>
  </button>
  <button>
    <span class="text">3</span>
  </button>
</div>
```

In my example I named the container `.pie`, here's the important CSS:

```css
.pie {
  border-radius: 50%;
  height: 150px;
  overflow: hidden;
  position: relative;
  width: 150px;
}
```
Height and width obviously only need to match each other, but could be anything.

Then you give the inner elements CSS to make them all appear initially as first-quarter quadrants of the pie container.

```css
button {
  bottom: 50%;
  height: 100%;
  left: 50%;
  position: absolute;
  transform-origin: bottom left;
  width: 100%;
}
```
What you have so far would look something like this:

![Quadrant](https://dev-to-uploads.s3.amazonaws.com/i/nwdp6zrrufsrtk4jwzbf.png)

The `transform-origin` probably seems out of place there, but it makes sense later, and is the key to the whole thing...

The final key to making the wedges is the calculation for transformation of each square into a wedge. This is done by using an ordered combination of: 

- `transform: rotate()`
- `transform: skeyY()`

To make the calculations we need to know the number of degrees each wedge should take in the circle. Let's say
`share = 120`
which is correct for our example with 3 equal shares, and we need an iterator, let's use
`i = 0`
*(I'm sure you can see how this will translate into a dynamic JS function for any number of wedges...)*

Now the calculation is as follows per wedge in order of appearance:

`rotate = (i * share)deg`
`skeyY = (share - 90)deg`
`i++`

**Minus 90 because the wedge starts out square**

Basically the rotation turns the wedge on it's bottom left corner (which is the center of the pie) the number of degrees of all the wedges that are before it. The skewY skews the wedge from being a rectangle to being a wedge of the right degrees.

Then we have to counter the skewY and rotation on the inner element (especially if you want text there), the calculation for that is:

`rotate = (share / 2)deg`
`skewY(-(share - 90)deg`

This will reverse the transformation and rotate the text to *appear* 45 degrees relative to it's containing 'wedge'.

Now your markup will look like this:

```html
<div class="pie">
  <button style="transform: rotate(0deg) skewY(30deg)">
    <span style="transform: skewY(-30deg) rotate(60deg)" class="text">1</span>    
  </button>
  <button style="transform: rotate(120deg) skewY(30deg)">
    <span style="transform: skewY(-30deg) rotate(60deg)" class="text">2</span>
  </button>
  <button style="transform: rotate(240deg) skewY(30deg)">
    <span style="transform: skewY(-30deg) rotate(60deg)"class="text">3</span>
  </button>
</div>
```

**Fair warning**
The order or the transform properties is important. Try switching the order and it won't work. I don't have enough time to figure that out, so if anyone here wants to explain that - go for it!

Here's how it looks in the end, with a bit of extra css so you can see the outcome better.

{% codepen https://codepen.io/tjbauwens/pen/bGepqoj default-tab=js,result %}

And if you're interested in making it dynamic, here's a very simple implementation:

{% codepen https://codepen.io/tjbauwens/pen/NWrrMPv default-tab=js,result %}

## Caveats and thoughts...

Don't try this on Internet Exploder - I haven't, and I won't...

The only real caveat is that you are limited to a minimum of three wedges. The maximum is really dependent on the inner content of the wedges as well as the overall size of the 'pie'... 

If you're interested, this could most likely be quite easily adapted into a simple pie chart engine - but I don't have the time to figure out the details.

Hope someone in need finds this, and it helps :-)