- var cardTextList = ['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vehicula enim quis lorem semper, non vulputate tortor auctor. In hac habitasse platea dictumst. Donec ac lorem ante.', 'Vestibulum elementum quam quis sem scelerisque, nec posuere leo sollicitudin. Quisque sed quam id ligula semper pellentesque cursus eu lectus. Sed congue orci quis nisi pulvinar, eu varius risus lacinia.', 'Donec sit amet mi rhoncus, tincidunt nulla vitae, pellentesque lectus.']

h1 Teach CSS - Card Flip
p Ever wonder how to create a card flip in CSS? Wonder no longer. In this example, I'll show how to achieve it with some CSS, and just the tiniest bit of JavaScript (which only toggles a CSS class!)
p Note, not all browsers support this trick, so be carefull!
h2 Example
div(class="card-list")
  each text, index in cardTextList
    div(class="card" onclick="flipCard(this)")
      div(class="card__back")
        p #{text}
      div(class="card__front")
        svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24")
          path(d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.507 13.941c-1.512 1.195-3.174 1.931-5.506 1.931-2.334 0-3.996-.736-5.508-1.931l-.493.493c1.127 1.72 3.2 3.566 6.001 3.566 2.8 0 4.872-1.846 5.999-3.566l-.493-.493zm-9.007-5.941c-.828 0-1.5.671-1.5 1.5s.672 1.5 1.5 1.5 1.5-.671 1.5-1.5-.672-1.5-1.5-1.5zm7 0c-.828 0-1.5.671-1.5 1.5s.672 1.5 1.5 1.5 1.5-.671 1.5-1.5-.672-1.5-1.5-1.5z")
h2 Walkthrough
p First we want our card to have a front and back side, so here's the HTML we'll want to build it.
pre(class="displayable-style").
  <div class="card">
    <div class="card__front">...content...</div>
    <div class="card__back">...content...</div>
  </div>
p Now for the CSS part. We want both sides of the card to be the full width and height of the card, and we want them positioned on top of each other. So for both, we'll absolutely position them, and set top, left, right, and bottom to 0 (also, make sure you give your card a width and height!)
p Now they are sitting on top of each other, and it's a hot mess. Content sitting on content. How do we deal with that? Two steps: we'll flip the card's back side component over, and hide the backface of it.
pre(class="displayable-style").
  .card__front,
  .card__back {
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
  }
  
  .card__back {
    transform: rotateY(180deg);
  }
p The `transform` rule will flip the card over, and that `backface-visibility` rule says that backface of the element isn't visible; i.e. when the element is flipped over and your looking at the back of the element, should you be able to see it or not? In our case, we don't want to see it.
p Sweet, there's our card! But at the moment we can't flip it over. Let's add that ability. First, we add an `onclick` listener to the card, which will just toggle if the card has the class `card--flipped`. But how does the CSS need to change to accomadate it?
pre(class="displayable-style").
  .card:not(.card--flipped) .card__back {
    transform: rotateY(180deg);
  }
  
  .card.card--flipped .card__front {
    transform: rotateY(180deg);
  }
p That's short and easy right? Any card that's not flipped should have it's card back component flipped over (so that we see the front). Any card that IS flipped over should instead have it's front side component flipped over (so that we see the back). Then all we need to do is add a transition for the transform, and there it is! Our finished card flip!
View Compiled
@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro');

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Source Sans Pro', sans-serif;
}

@mixin center-content() {
  display: flex;
  align-items: center;
  justify-content: center;
}

body {
  margin: auto;
  height: 100vh;
  max-width: 800px;
  width: 100%;
}

.card-list {
  @include center-content();
}

.card {
  position: relative;
  height: 300px;
  width: 225px;
  cursor: pointer;
  
  & + .card {
    margin-left: 30px;
  }
  
  .card__front,
  .card__back {
    @include center-content();
    
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    border: 1px solid #CCC;
    border-radius: 5px;
    box-shadow: 1px 2px 4px #333;
    height: 300px;
    width: 225px;
    transition: transform .5s;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
  }
  
  &:not(.card--flipped) .card__back {
    transform: rotateY(180deg);
  }
  
  &.card--flipped .card__front {
    transform: rotateY(180deg);
  }
  
  p,
  svg {
    width: 90%;  
  }
}

h1,
h2 {
  text-align: center;
}

h1 {
  margin: 30px;
}

h2 {
  margin: 30px;
}

p,
.displayable-style {
  margin: 20px 30px;
}

.displayable-style {
  display: block;
  padding: 10px 20px;
  background-color: #333;
  color: #FFF;
  font-family: monospace;
}
View Compiled
// callback for card click
function flipCard(self) {
  self.classList.toggle('card--flipped');
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.