CSS: 3 Sided Card
Tags: css, webdev, tutorial, showdev
Published: 2023-01-17 19:08:18

The other day I was tasked with creating a "3 sided card" that flips. It proved more challenging than I thought, though the solution isn't that complex.

## What we're building

Calling it a "3 sided card" is misleading, but when I first started trying to build this, that's all I could think to call it.

In reality, it is [pentahedron](https://en.wikipedia.org/wiki/Pentahedron) — in particular, a triangular prism. Imagine a cube where you remove one side, and then fold the adjoining two together. 

<img src="https://upload.wikimedia.org/wikipedia/commons/2/21/Triangular_prism.png" />

The final product can be found at the [end](#live).

## The gist

The structure consists of three `div`s making up the sides, wrapped in a `div` for the prism.

```html
<div class="prism">
  <div class="side one">1</div>
  <div class="side two">2</div>
  <div class="side three">3</div>
</div>
```

We don't need to worry about the top and bottom.

The css is little more complicated. First, some non-critical styling to make it look nice.

```css
.prism {
  margin: auto;
  width: 100px;
  aspect-ratio: 1 / 1;
}

.side {
  border: 1px solid black;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.one {
  background-color: #63cdda;
}

.two {
  background-color: #ea8685;
}

.three {
  background-color: #f5cd79;
}
```

## The good stuff

Making this relies heavily on the [`rotate3d`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate3d) function, which I'll talk about in the next section.

For now, let's define the css for the prism and it's sides.

### css

```css
.prism {
  transition: transform 0s linear;
  transform-style: preserve-3d;
}
```
On the prism div, we define a `transition` for when the `transform` property changes. This will define how fast the card changes.

It's currently set at `0s` for accessibility.

Below it we can define a media query for if the user has no preference for reduced motion.

```css
@media (prefers-reduced-motion: no-preference) {
  .prism {
    transition: transform 0.5s linear;
  }
}
```

This will give the card a spin.

We will apply a transform in the next section.

Now the sides.

```css
.side {
  position: absolute;
  height: 100%;
  width: 100%;
}
```

This ensures each side takes up the whole face of the prism.

Lastly, we add a transform property to each side.

```css
.side.one {
  transform: rotateY(0deg) translateZ(29px);
}

.side.two {
  transform: rotateY(120deg) translateZ(29px);
}

.side.three {
  transform: rotateY(240deg) translateZ(29px);
}
```

Each side is rotated on it's Y-axis 120deg (i.e. 360/3).

The `translateZ` property was a bit of a guessing game. It's related to the width of the prism, but I had to figure out the right value by trial-and-error.

### Html and JavaScript

Now, I haven't talk about `rotate3d` property yet. Before we add it, we're going to add a data attribute to the prism.

```html
<div class="prism" data-degrees="0">
  <div class="side one">1</div>
  <div class="side two">2</div>
  <div class="side three">3</div>
</div>
```

Now we can manipulate the data attribute with JS and apply a `rotate3d` value based off of the data attribute.

```js
function toggleDegrees(e) {
  const currentDegrees = +e.currentTarget.dataset.degrees || 0;
  const newDegrees = currentDegrees + 120;
  e.currentTarget.style.transform = `rotate3d(0, -1, 0, ${newDegrees}deg)`;
  e.currentTarget.dataset.degrees = newDegrees;
}

document.querySelector(".prism").addEventListener("click", toggleDegrees);
```

By constantly increasing the degree, instead of setting it back to `0`, the card will keep spinning in one direction.


## Live

{% codepen https://codepen.io/charles-loder/pen/QWBqrNN %}

## Conclusion

I hope someone else finds this useful. I wanted to get thoughts typed out before I forget how to do this.

Any suggestions are welcomed!