Make Amazing CSS 2D Card With Flipping Animation On Hover

Marilena

By Marilena

14 min read
Bookmark this post

Hello! In this post, I will show you how to create a visually appealing CSS 2d card with flipping animation that activates when you hover over it. To enhance the design, I have added an avatar and integrated the animation with it. If you are interested in how I created the avatar, you can check out the complete avatar code at the end of this post. You are free to use it in your animation or customize it to your liking. Enjoy! 😉

For now, let’s move forward and create this incredible animation!

CSS Flipping card animation on hover

The following HTML and SCSS (Sass) code makes a card flip around. Using the X-axis and Y-axis which are two lines that intersect, helps us determine the position of a point in a two-dimensional area.

Let’s analyze our code one step at a time:

HTML structure

We will begin with the HTML structure. We create a parent container called .flip-wrapper. This container acts as the parent element for our animation. Inside it, we have a child element with the .flip-card class, this is where our animation happens. Next, we divide the child element into two parts: the front side and the back side. On the front side, we’ll add the .avatar-container and place the avatar inside while on the back side, we’ll add the .text-container class and add some text.

<div class="flip-wrapper">
  <div class="flip-card">
    <div class="avatar-container"></div>
    <div class="text-container">
      <h1>Hello</h1>
      <div><i>How are you today?</i></div>
    </div>
  </div>
</div>
HTML

CSS Basic structure

In our CSS code snippet, first of all, we set the background of our whole page to pink. 💕 🎀 🌸

Moving on to the .flip-wrapper container, we specify its dimensions, giving it a fixed width and height of 300 pixels. To make a circular appearance, we apply a border-radius of 50%. If you desire, you can maintain the square ⬜ shape. I chose this rounded ⚪ design because it makes it easier for us to observe the effect we’re aiming for. 😉

Next, we focus on the .flip-card element. We set the position: relative property and then its witdh and height to 100% to ensure it covers the entire available space. We also add a white background-color and a subtle gray shadow effect. To maintain the circular theme, we apply a border-radius of 50% to this container too.

Finally, we set the position: absolute property in both .avatar-container and .text-container classes. In that way we will be ready to place the content we want on both, the front and the back, sides of our card.

body {
  background: pink;
}

.flip-wrapper {
  width: 300px;
  height: 300px;
  border-radius: 50%;
  .flip-card {
    position: relative;
    width: 100%;
    height: 100%;
    background-color: white;
    box-shadow: inset 0 0 15px grey;
    border-radius: 50%;
  }
}

.avatar-container,
.text-container {
  position: absolute;
}
SCSS

This is what’s rendered on our screen at the moment.

Adding the hover effect

In order for our effect to function as intended we have to work with both the parent and the child element. We begin with the parent element, where we apply the :hover effect and change the cursor to a pointer (you can pick any cursor style you prefer).

.flip-wrapper {
  ...
  &:hover {
    cursor: pointer;
  }
}
SCSS

Preparing the front side of my flipping card

I added an avatar on the front side of my flipping card. You can add whatever you want (some text, maybe, or an emoticon ✏️) or you can leave it empty, though it is not really useful for observing the flipping.

.avatar-container {
  ...
}
SCSS

In the following image, we can see how the front side of our flipping card would be. Nice! Isn’t it? 😃

Preparing the back side of my flipping card

Here we prepare our text’s style. We keep the default black color and we centered our text based on the display: flex method.

.text-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
SCSS

Below we can see how the back side of our flipping card would be. Cool huh! 😃

Now we are ready to connect these two parts and finally create our amazing animation.

Adding the flipping animation at the 2D card

We are free to create flipping animations on both axis X and Y. Below, I prepared two examples. The first one is for axis-Y while the second one is for axis-X. Let’s break it down and see them analytically. 🧐

Flipping animation on axis-Y

In order to achieve our goal we have to combine the following CSS properties.

  1. transform: rotateY(180deg) We begin by setting the transform property, which is responsible for the flipping, inside the hover effect. It is also necessary to add it to the class that represents the back side of our card, in our case the .text-container class, otherwise, our text won’t be rendered on the screen when we hover over the card.
  2. transition: transform 6s & transform-style: preserve-3d We continue by combining these two properties inside the .flip-card class. The first one shows us the exact, time in seconds (s), our effect will take place while the second one makes the children of an element appear as if they are positioned in a 3D space. So this property gives us the impression that the descendants (children) of our element are located within a three-dimensional space.
  3. backface-visibility: hidden We finalize our work with the backface-visibility property that defines whether or not the back side of an element should be visible when facing the user. The back face of an element is a mirror image of the front face being displayed.
.flip-wrapper {
  ...
  &:hover {
    cursor: pointer;
    .flip-card {
      transform: rotateY(180deg);
    }
  }
  .flip-card {
    ...
    transition: transform 6s;
    transform-style: preserve-3d;
  }
}

.avatar-container,
.text-container {
  ...
  backface-visibility: hidden;
}

.text-container {
  transform: rotateY(180deg);
}
SCSS

Voila!! Here is our amazing flipping 2d card animation for the Y-axis!! 🥳

Flipping animation on axis-X

We do as previously but in this case, we set the transform: rotateX as we want our animation to move along the X-axis.

.flip-wrapper {
  ...
  &:hover {
    cursor: pointer;
    .flip-card {
      transform: rotateX(180deg);
    }
  }
  .flip-card {
    ...
    transition: transform 6s;
    transform-style: preserve-3d;
  }
}

.avatar-container,
.text-container {
  ...
  backface-visibility: hidden;
}

.text-container {
  transform: rotateX(180deg);
}
SCSS

Boom! 🎉 This is our wonderful flipping 2d card animation for the X-axis!!

Complete avatar code

Below, I include my HTML and CSS avatar code.

<div class="avatar-container">
  <div class="hair-back"></div>
  <div class="hair hair--left"></div>
  <div class="hair hair--right"></div>
  <div class="hair-clip hair-clip--left"></div>
  <div class="hair-clip hair-clip--right"></div>
  <div class="ear ear--left"></div>
  <div class="ear ear--right"></div>
  <div class="face">
    <div class="eyebrow1 eyebrow1--left"></div>
    <div class="eyebrow1 eyebrow1--right"></div>
    <div class="eyebrow2 eyebrow2--left"></div>
    <div class="eyebrow2 eyebrow2--right"></div>
    <div class="eye-glasses eye-glasses-left"></div>
    <div class="eye-glasses eye-glasses-right"></div>
    <div class="eye eye--left">
      <div class="eyelash eyelash--left"></div>
      <div class="eyelash eyelash--left1"></div>
      <div class="eyelash eyelash--left2"></div>
      <div class="eyelash eyelash--left3"></div>
      <div class="eyelash eyelash--left4"></div>
    </div> <!-- end of left eye -->
    <div class="eye eye--right">
      <div class="eyelash eyelash--right"></div>
      <div class="eyelash eyelash--right1"></div>
      <div class="eyelash eyelash--right2"></div>
      <div class="eyelash eyelash--right3"></div>
      <div class="eyelash eyelash--right4"></div>
    </div> <!-- end of right eye -->
    <div class="nose"></div>
    <div class="lips"></div>
  </div> <!-- end of face -->
  <div class="neck"></div>
  <div class="t-shirt"></div>
  <div class="neckless"></div>
</div> <!-- end of avatar-container -->
HTML
Expand
$body-color: #ff9aab;
$container-color: white;
$skin-color: #eabcb4;
$primary-color: #2d2a2a;
$secondary-color: #f1f1f1;
$eye-color: #17884e;
$eyeline-color: #5b3a3a;
$eyelash-color: #6d4646;
$iris-color: #000;
$hair-color: #dfc2ae;
$hair-clip-color1: green;
$hair-clip-color2: #b3498d;
$hair-clip-color: linear-gradient($hair-clip-color1, $hair-clip-color2, $hair-clip-color1, $hair-clip-color2, $hair-clip-color1);
$eye-glasses-color: #a32a80;
$eyebrow-color: #5b3a3a;
$nose-color: #646363;
$lips-color: #cd0b87;
$t-shirt-color: #0b443c;
$neckless-color: #0b443c;

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  height: 100vh;
}

body {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: $body-color;
}

.avatar-container {
  position: relative;
  width: 320px;
  height: 320px;
  border-radius: 50%;
  background-color: $container-color;
  box-shadow: inset 0 0 15px grey;
  overflow: hidden;
  .hair-back {
    position: absolute;
    width: 140px;
    height: 200px;
    border-radius: 44% 44% 20px 20px;
    top: 30px;
    left: 50%;
    transform: translate(-50%);
    background-color: $hair-color;
    filter: drop-shadow(0 0 2px #bc9b83);
    z-index: 2;
    &:before {
      content: "";
      position: absolute;
      width: 0.5px;
      height: 28px;
      background-color: #bc9b83;
      filter: drop-shadow(0 0 4px #69660f);
      top: 0px;
      left: 50%;
      transform: translate(-50%);
    }
    &:after {
      content: "";
      position: absolute;
      width: 100px;
      height: 110px;
      border-radius: 20%;
      background-color: #d8baa4;
      top: 70px;
      left: 50%;
      transform: translate(-50%);
    }
  }
  
  .hair {
      position: absolute;
      width: 40px;
      height: 40px;
      background-color: $hair-color;
      filter: drop-shadow(0 0 2px #bc9b83);
      z-index: 1;
      &--left {
        border-radius: 50% 50% 70% 70%;
        top: 22px;
        left: 80px;
        transform: rotate(-50deg);
      }
      &--right {
        border-radius: 50% 50% 60% 60%;
        top: 22px;
        right: 80px;
        transform: rotate(50deg);
      }
    }
  
  .hair-clip {
    position: absolute;
    width: 28px;
    height: 6px;
    background: $hair-clip-color;
    box-shadow: 0 0 2px #037203;
    border-radius: 20%;
    z-index: 10;
    &--left {
      transform: rotate(-50deg);
      top: 48px;
      left: 98px;
    }
    &--right {
      transform: rotate(50deg);
      top: 48px;
      right: 98px;
    }
  }

  .ear {
    position: absolute;
    width: 10px;
    height: 20px;
    background-color: $skin-color;
    filter: drop-shadow(0 0 1px #7e7a1f);
    border-radius: 40%;
    top: 95px;
    z-index: 3;
    &--left {
      left: 104px;
      transform: rotate(-5deg);
      &:before {
        content: "";
        position: absolute;
        width: 6px;
        height: 12px;
        background-color: $skin-color;
        border-radius: 40% 40% 50% 50%;
        box-shadow: -1px -1px 1px darken($skin-color, 10%);
        top: 3px;
        left: 2px;
      }
    }
    &--right {
      right: 104px;
      transform: rotate(5deg);
      &:before {
        content: "";
        position: absolute;
        width: 6px;
        height: 10px;
        background-color: $skin-color;
        border-radius: 40% 40% 50% 50%;
        box-shadow: 1px -1px 1px darken($skin-color, 10%);
        top: 3px;
        right: 2px;
      }
    }
  } // end of ear

  .face {
    position: absolute;
    width: 100px;
    height: 110px;
    border-radius: 100% / 70% 70% 160% 160%;
    background-color: $skin-color;
    top: 54px;
    left: 50%;
    transform: translate(-50%);
    box-shadow: 0 0.5px 2px #b37865;
    z-index: 10;
        
    .eye-glasses {
    position: absolute;
    width: 40px;
    height: 32px;
    border: 3px solid $eye-glasses-color;
    top: 32px;
    z-index: 10;
    &.eye-glasses-left {
      border-radius: 12px 18px 18px 18px;
      left: 5px;
      &:before {
        content: "";
        position: absolute;
        width: 14px;
        height: 3px;
        background-color: $eye-glasses-color;
        top: 10px;
        left: 35px;
      }
      &:after {
        content: "";
        position: absolute;
        width: 6px;
        height: 3px;
        background-color: $eye-glasses-color;
        top: 8px;
        left: -8px;
      }
    }
    &.eye-glasses-right {
      border-radius: 18px 12px 18px 18px;
      right: 5px;
      &:before {
        content: "";
        position: absolute;
        width: 15px;
        height: 3px;
        background-color: $eye-glasses-color;
        top: 6px;
        left: -15px;
      }
      &:after {
        content: "";
        position: absolute;
        width: 6px;
        height: 3px;
        background-color: $eye-glasses-color;
        top: 8px;
        right: -8px;
      }
    }
  }  // end of eye-glasses

    .eye {
    position: absolute;
    width: 20px;
    height: 20px;
    top: 38px;
    background-color: $secondary-color;
    border: 2px solid $eyeline-color;
    border-radius: 75% 0%;
    transform: rotate(45deg);
    &:before {
      content: "";
      position: absolute;
      width: 10px;
      height: 10px;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background-color: $eye-color;
      border-radius: 50%;
      box-shadow: inset 1px 1px 1px 1px #17460d;
    }
    &--left {
      left: 16px;
      box-shadow: -1px 0 2px darken($eyeline-color, 50%);
    }
    &--right {
      right: 16px;
      box-shadow: 0 -1px 2px darken($eyeline-color, 50%);
    }
    &:after {
      content: "";
      position: absolute;
      width: 4px;
      height: 4px;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background-color: $iris-color;
      border-radius: 50%;
    }
      .eyelash {
      position: absolute;
      Width: 1px;
      height: 5px;
      background-color: $eyelash-color;
      &--left,
      &--left1,
      &--left2,
      &--left3,
      &--left4 {
        transform: rotate(90deg);
      }
      &--left {
        top: -2px;
        left: 1px
      }
      &--left1 {
        top: 1px;
        left: -2px
      }
      &--left2 {
        top: 5px;
        left: -5px
      }
      &--left3 {
        top: 9px;
        left: -6px
      }
      &--left4 {
        top: 13px;
        left: -6px
      }
      &--right {
        top: -2px;
        right: 14px;
      }
      &--right1 {
        top: -5px;
        right: 10px;
      }
      &--right2 {
        top: -7px;
        right: 6px;
      }
      &--right3 {
        top: -8px;
        right: 2px;
      }
      &--right4 {
        top: -8px;
        right: -1px;
      }
    } // end of eye-lash
  } // end of eye
     
    .eyebrow1 {
      position: absolute;
      width: 20px;
      height: 3px;
      background-color: $eyebrow-color;
      border-radius: 50%;
      top: 28px;
      &--left {
        transform: rotate(10deg);
        left: 16px;
      }
      &--right {
        transform: rotate(-10deg);
        right: 16px;
      }
    } // end of eyebrow1 //
    .eyebrow2 {
        position: absolute;
        content: "";
        width: 14px;
        height: 2px;
        background-color: $eyebrow-color;
        border-radius: 50%;
        top: 28px;
        &--left {
          transform: rotate(-12deg);
          left: 9px;
        }
        &--right {
          transform: rotate(12deg);
          right: 9px;
        }
      } // end of eyebrow2 //
    
    .nose {
      position: absolute;
      width: 5px;
      height: 2px;
      background-color: $nose-color;
      border-radius: 50%;
      transform: rotate(45deg);
      top: 70px;
      left: 44px;
      &:before {
        content: "";
        position: absolute;
        width: 5px;
        height: 2px;
        background-color: $nose-color;
        border-radius: 50%;
        transform: rotate(90deg);
        top: -6px;         
        left: 6px;
        }
    } // end of nose

    .lips {
    position: absolute;
    width: 18px;
    height: 18px;
    border-radius: 90% 0;
    background-color: darken($lips-color, 1%);
    top: 90px;
    left: 50%;
    transform: rotate(45deg) translate(-60%);
    &:before {
      content: "";
      position: absolute;
      width: 0;
      height: 0;
      border-left: 3px solid transparent;
      border-right: 3px solid transparent;
      border-top: 3px solid $skin-color;
      border-radius: 60%;
      transform: rotate(-45deg);
      top: 24%;
      left: 12%;
    }
  }  // end of lips
} // end of face 

  .neck {
    position: absolute;
    width: 34px;
    height: 50px;
    background-color: $skin-color;
    filter: drop-shadow(0 0 2px #865748);
    top: 149px;
    left: 50%;
    transform: translate(-50%);
    z-index: 9;
    &:before {
      content: "";
      position: absolute;
      width: 60px;
      height: 40px;
      background-color: $skin-color;
      border-radius: 50%;
      top: 40px;
      left: 50%;
      transform: translate(-50%);
    }
  } // end of neck

  .t-shirt {
    position: absolute;
    width: 166px;
    height: 140px;
    background-color: $t-shirt-color;
    border-radius: 100% / 50% 50% 20% 20%;
    top: 190px;
    left: 50%;
    transform: translate(-50%);
    filter: drop-shadow(0 0 2px);
    z-index: 4;
  } // end of t-shirt
  
  .neckless {
    content: "";
    position: absolute;
    width: 36px;
    height: 10px;
    background-color: $neckless-color;
    border-radius: 2px 2px 0 0;
    z-index: 10;
    top: 183px;
    left: 50%;
    transform: translate(-50%);
  } // end of neckless
} // end of avatar-container
SCSS
Expand

🌼 Hope you found my post interesting and helpful. Thanks for being here! 🌼

DigitalOcean Referral Badge
guest
0 Comments
Inline Feedbacks
View all comments

Continue reading

Front, Programming

Learn How to Select Only the CSS First Child

Front, Programming

The CSS nth-of-type Selector – How To Target Elements By Type

Front, Programming

What You Need to Know About CSS nth child Selector – A Practical Guide

Front, Programming

CSS Selectors nth-child VS nth-of-type And How To Use Them Correctly

Front, Programming

Coding Made Easy With CSS Selectors: An Ultimate Guide

Front, Programming

How to Center in CSS Using Different Ways

Front, Programming

What You Need to Know About CSS Color Methods

Programming

Most Common Typescript Errors and How to Solve Them

Front, Programming

Make Your Work Easier by Using Variables in CSS

Front, Programming

CSS Rainbow Text: How To Make Astonishing And Vibrant Fonts

Front, Programming

Most Useful HTML Elements for Maximizing Better Results

Back, Programming

Environment Variables 101: Secure Your Secrets Like a Pro

Subscribe to our newsletter

Dive into the Fun Side of Tech! Posts, News, and More Delivered to Your Inbox!

Intuit Mailchimp