Multi-faced Flip Card with a Click (Part 2: CSS)
Tags: css, tutorial, flipcard
Published: 2020-06-30 19:12:08

_More than just your average **Flip Card** tutorial. Don’t just flip your card on hover, use JavaScript to flip it on command. Includes instructions on how to change the reverse face to show a different face each time and tricks to give the card a nice 3D effect while flipping._

This series will be divided into three parts (plus a fun bonus at the end): 
* Part I: [HTML](https://dev.to/santiagocodes/multi-faced-flip-card-with-a-click-part-i-o6c)
* Part II: [CSS](https://dev.to/santiagocodes/multi-faced-flip-card-with-a-click-part-2-css-3oam)
* Part III: [JavaScript](https://dev.to/santiagocodes/multi-faced-flip-card-with-a-click-part-3-javascript-2f7f)
* Bonus: [Going further into 3D space](https://dev.to/santiagocodes/multi-faced-flip-card-with-a-click-bonus-going-further-into-3d-space-2jff)

___

# Part II: The CSS

I will be covering this part by starting from the card outline and working my way in. There will be some explanation about what each declaration is doing, and I will provide links for those of you that want to understand each property further.

> In case you feel like you need to review your CSS basics, click [here](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/CSS_basics).

## The Container

Let’s start with the `.card__container` selector, which refers to the outline `<div>` of our card, and give it the desired width and height. You can choose different [CSS units](https://www.freecodecamp.org/news/css-unit-guide/) for this. I used absolute units by setting both the width and the height to 350px, but you can use relative units (e.g. em, %, vw, vh) if it suits you best for responsiveness. 

The last property is a new one for me, at least until a week ago, called `perspective`. As I mentioned in Part I, the container will stay static and the content will be the one doing the flip. By adding a `perspective` property to the container of our card we will be giving the child element, which in our case will be the `.card__content`, a perspective view. As for the property value, a lower number will give you a more intense 3D effect. (Once the project is up and running, try changing the perspective from 350px to 50px and see how freaky it looks. For now, you won’t notice anything though so just keep it in mind for later). 

```css
.card__container {
  width: 350px;
  height: 350px;
  perspective: 350px;
}
```

## The Content 

With width and height both set to 100%, our `.card__content` will take up all the space of the parent element, which is that of the `.card__container` that we just set up a moment ago. The `position` property will be set to `relative`. 

The [transform-style](https://www.w3schools.com/cssref/css3_pr_transform-style.asp) property set to `preserve-3d` does exactly as it states. This will preserve the 3D appearance of the element as it flips. This effect is only appreciated when applying the `transform` property, which we will be adding to the `.card__content.is-flipped` selector. (This new `.is-flipped` class will be of use to us on the next part of the series.)

You could set the `transform` property to rotate 180 degrees on the y-axis alone, but adding a few extra things, like `translateX(-100%)` alongside the [transform-origin](https://css-tricks.com/almanac/properties/t/transform-origin/) property will give the flip a nice effect, although this is optional. 

The `transform-origin` default value is `50% 50%`, which is the center of the element. When the transformation is applied to the element and the `transform-origin` is set to `center right` the rotation’s axis will move to the center of the right-hand edge. You can better understand this concept if you play with the values and see the effects yourself. 

{% codepen https://codepen.io/santiagocodes/pen/yLePNGp %}

The `transform-style` and `transform-origin` properties only work when you have a `transform` property on the element. On the other hand, the [transition](https://www.w3schools.com/css/css3_transitions.asp) property works on any property. This is used to allow a smooth transition when there is a change detected in the property selected. In our case we set the transition a value to `transform 2s`. This means that when the transform property changes it won’t do so abruptly, but will do so over two seconds. You can change this, but I found that 1 second was too quick, and although 3 seconds was acceptable, it was a bit too slow for my taste. 

```css 
.card__content {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transform-origin: center right;
  transition: transform 2s;
}

.card__content.is-flipped {
  transform: translateX(-100%) rotateY(-180deg);
}
```

## The Faces

Now, let’s move on to the content on the front and back of the card. Most of the properties will be the same for these two, except for a few differences. We can group the equal declarations under a class name like I did with `.card-face`, or you could skip adding that extra class to those `<div>`s and group the front and back selectors with a comma at the center like so `.card-front, .card-back{ property: property-value; }`. The choice is yours. 

I won’t explain those declarations that are for aesthetics purposes, but I will explain how the other ones will help us get our flip card working. We previously set the `position` of the `.card__content` to `relative`, and that had to do with the next property we will be adding to the face of the card. With a declaration of [position: absolute](https://css-tricks.com/almanac/properties/p/position/) the reverse face of the card will be revealed in the same position as the front face of the card, and not below as the space the two elements take up will be one on top of the other.  

This next part is a little difficult to explain, but bear with me. Take two pieces of paper (one to represent the `.card-front` and another to represent the `.card-back` of the card) and have them both facing you. When you simulate the flip action, what do you get? You get the back of the `.card-back`. That is not what we want, which is why we will initially rotate `.card-back` 180 degrees (or half a turn) on the y-axis. Do the same to your piece of paper and try again. 

One of the tricks to getting the reverse face to show different results is to set all of the `.card-back`s to `display: none;` and using JavaScript to change that declaration to `display: block;` the one we want (you’ll see more about this on Part III of the series). 

Now, the `.card-back` of the card won’t always be the face of the card facing backwards, which is why we add the `backface-visibility: hidden;` declaration to both faces of the card. This means that whichever face is at the back will be hidden and won’t ruin the aesthetic of the face that is showing. 

```css
.card__face {   /* -same as- .card-front, .card-back { */
  position: absolute;
  width: 100%;
  height: 100%;   
  background: rgba(10,10,10,0.8);   /* aesthetic  */
  box-shadow: 0 0 10px 8px rgba(255,0,0,0.75);   /* aesthetic  */
  border-radius: 5px;   /* aesthetic  */
  text-align: center;    /* aesthetic  */
  backface-visibility: hidden;
}

.card__back {
  transform: rotateY(180deg);   /* -same as- transform: rotateY(0.5turn); */
  display: none;
}

.card__back.display {
  display: block;
}
```

## The Front of the Card (optional)

This next part you can change to whatever you want. Since the following is all about the aesthetics of the front of the card I won’t explain it, but I will explain a little bit about the [selectors](https://www.w3schools.com/cssref/css_selectors.asp) used. 

When I use something like `.card__front > h2` this means that the ruleset that follows will only be applied to the `<h2>` tags where the parent is `.card__front` class. When using something like `#input__form:hover` this means that the ruleset will be applied when the user is hovering over the element with the `id` of `#input__form`. That `:hover` is a [CSS pseudo class](https://www.w3schools.com/css/css_pseudo_classes.asp), just like `.btn:active` where the ruleset will be applied for selected links with a `.btn` class. 

If you have any questions I do encourage you to comment down below and I will get back to you. 

> FYI: Selectors starting with `#` are `id`s and selectors starting with `.` are classes. Also, remember that `id`s are unique to one element. 

HTML:
```html
<!--       Front of the card -->
<div class="card__face card__front">
    <h2>Planck's Constant</h2>
    <form>
       <input 
               id="input__form"
               type="number" 
               step="0.00000001" 
               min="6" max="7" 
               placeholder="Enter Number" 
               required="required" />
       <button class="btn" type="submit">Validate</button>
    </form>
</div>
```

CSS:
```css
.card__front {
  padding: 40px 20px;
}

.card__front > h2 {
  text-align: center;
  margin: 0;
  font-weight: 900;
  padding-bottom: 0.5em;
  color: white;
  text-shadow: -0.05rem -0.05rem 5px rgba(237, 43, 18, 1);
  font-size: 2rem; 
}

.card__front > form {
  margin-top: 25px;
}

.card__front > form input {   <!-- -same as-  #input__form { -->
  padding: 10px;
  border: 1px solid rgba(0,0,0,0.1);
  background-color: #ddd;
  box-shadow: 0 0 5px 3px rgba(255,0,0,0.4);
  border-radius: 5px;
}

.card__front > form input:hover {    <!-- -same as-  #input__form:hover { -->
  background-color: #eee;
  box-shadow: 0 0 7px 5px rgba(255,0,0,0.4);
}

.btn {
  margin: 5px;
  padding: 10px;
  outline: 0;
  border: 1px solid rgba(0,0,0,0.1);
  background-color: transparent;
  box-shadow: 0 0 5px 3px rgba(255,0,0,0.4);
  color: white;
  border-radius: 10px;
}

.btn:hover {
  background-color: #000;
  box-shadow: 0 0 7px 5px rgba(255,0,0,0.4);
}

.btn:active {
  background-color: #333;
}
```

The result for the front of the card should look something like this: 

[![chrome-JGf-Qsmld-DA.png](https://i.postimg.cc/pXHjB5s9/chrome-JGf-Qsmld-DA.png)](https://postimg.cc/4nWnfykZ) 

## The Back of the Card (optional) 

Same as the previous section, I won’t explain the code below but if you have any questions feel free to comment down below and I will get back to you on that.

Do keep in mind that in this case, the 3 options we have for the back of the card have the same layout. I only changed the `src` of the image and the text of the button, but this doesn’t have to be the case. You can add an `id` to each face of the card and have completely different card layouts for each of them. 

For example, I have a `#card__back__one > p` selector because I have a paragraph that I needed to style on `#card__back__one` that does not exist on `#card__back__two` nor on `#card__back__three`. Remember that each one is literally a completely different face so you can do with them what you want. 

HTML:
```html
<!--       Back of card__back__one if 6.62607015 -->
      <div id="card__back__one" class="card__face card__back">
        <img 
             class="image__back" 
             src="https://i.postimg.cc/BZpQPT4M/stranger-things-lights.jpg" 
             alt="Kareen Wheeler happy"/>
        <p>You Got It!</p>
        <button id="btn__back__one" class='btn btn__back'>Reset</button>
      </div>
<!--       Back of card__back__two if 6.62607004 -->
      <div id="card__back__two" class="card__face card__back">
        <img 
             class="image__back" 
             src="https://i.postimg.cc/hjrgxnWf/susie-constante-planck.jpg" 
             alt="Susie's Planck's Constant is 6.62607004."/>
        <button id="btn__back__two" class='btn btn__back'>Reset</button>
      </div> 
<!--       Back of card__back__three if default -->
      <div id="card__back__three" class="card__face card__back">
        <img 
             class="image__back" 
             src="https://i.postimg.cc/tTTkpd57/robin-stranger-things-you-suck.jpg" 
             alt="Robin thinks you suck."/>
        <button id="btn__back__three" class='btn btn__back'>Try Again</button>
      </div> 
```

CSS:
```css
.image__back {
  width: 100%;
  height: 100%;
  margin: 0px;
  padding: 2px;
  box-shadow: 0 0 0 1px rgba(255,0,0,0.55);
  border-radius: 5px;
}

#card__back__one > p {
  color: #111;
  text-shadow: -0.05rem -0.05rem 5px rgba(237, 43, 18, 1);
  font-size: 2em;
  font-weight: 700;
  text-align: center;
  margin-top: -50px;
}

.btn__back {
  position: absolute;
  top: 8px;
  right: 8px;
  background: rgba(10,10,10,0.8);
}

```

The result for the back of the card (in this case, of `#card__back__three`) should look something like this: 

[![chrome-WTf-ECM5ol-I.png](https://i.postimg.cc/zvfsmGjT/chrome-WTf-ECM5ol-I.png)](https://postimg.cc/ygwQcB2N)

## Extra Asethetic Features 

I know there are certain things (like the *Stranger Things* logo) that I didn’t mention in this part, but I will be adding the codepen with the whole project on Part III so you can take a look at those bits that have nothing to do with the actual action of flipping the card in the next part of this series. 

Remember to comment below if you have any questions or suggestions. In the next part of this series, we will be looking into the JavaScript of this project.

:computer: **article.close()**

## Resources

* [w3schools's How To - Flip Card](https://www.w3schools.com/howto/howto_css_flip_card.asp)
* [CSS Basics](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/CSS_basics)
* [selectors](https://www.w3schools.com/cssref/css_selectors.asp)
* [CSS pseudo class](https://www.w3schools.com/css/css_pseudo_classes.asp)
* [transform-style](https://www.w3schools.com/cssref/css3_pr_transform-style.asp)
* [transform-origin](https://css-tricks.com/almanac/properties/t/transform-origin/)
* [transition](https://www.w3schools.com/css/css3_transitions.asp)
* [position: absolute](https://css-tricks.com/almanac/properties/p/position/)
* [Stranger Things Logo](https://pixabay.com/illustrations/stranger-things-serie-horror-tv-4337985/)
* [PostImages](https://postimages.org/): Get permanent links for Facebook, Twitter, message boards and blogs.