Pure CSS Flip Cards using Bootstrap 4 and CSS Grid [No JS]


Pure CSS Flip Cards using Bootstrap 4 and CSS Grid [No JS]
Last Updated: Feb 19, 2020

Nicolas Kadis |

The Problem

I've wanted to create flipping cards for my website that would resize on different screen sizes using Bootstrap 4's .card class. At first I wanted to find a solution that was purely HTML and CSS. So I started searching online for some answers, but almost all of them lead to either having to set a fixed width, fixed height or too much JavaScript (or even combinations).

I finally realised that I had to combine some of the features on all the code I had seen to make it work. After a lot of tinkering around with bits of code, I came across a video about CSS Grid by Morten Rand-Hendriksen. After watching it I realised that I could use CSS Grid to stack two objects in the same location and use some basic transformations to create my Flipping Cards.

The Solution

The most important part of creating a flipping object is the structure of your HTML. You need:

  • A container to hold the two cards
  • A flipper to carry out the transformation (rotate 180 degrees)
  • A container for the front side
  • A container for the back side

So your structure should look something like this:

<div class="card-container">
    <div class="card-flip">
        <div class="front">
            <!-- card content -->
        </div>
        <div class="back">
            <!-- card content -->
        </div>
    </div>
</div>

Now that we have the basic HTML needed for our flipping cards, we need the appropriate CSS to make the content flip:

.card-container {
    perspective: 700px;
}

.card-flip, .card-container {
    transform-style: preserve-3d;
    transition: all 0.7s ease;
}

.card-flip div {
    backface-visibility: hidden;
    transform-style: preserve-3d;
}

.back {
    transform: rotateY(-180deg);
}

.card-container:hover .card-flip {
    transform: rotateY(180deg);
}

To break this down:

  • perspective is used to allow a 3D effect for our transformation.
  • transform-style: preserve-3d keeps the 3D effect during transformations.
  • transition eases the transformation effect to make it look nicer.
  • backface-visibility: hidden just hides the back sides of each card.
  • transform is used to:
    1. rotate the back side by 180 degrees so that when the front side is shown, the back side is hidden.
    2. rotate the flipper by 180 degrees so that both cards inside the container flip by 180 degrees.

Now the problem is that our cards do not stack up. This is where CSS Grid comes in handy!

To make our cards stack up, we need to make some small additions to our CSS:

.card-flip {
    display: grid; grid-template: 1fr / 1fr;
    grid-template-areas: "frontAndBack";
    transform-style: preserve-3d;
    transition: all 0.7s ease;
}

.front {
    grid-area: frontAndBack;
}

.back {
    grid-area: frontAndBack;
    transform: rotateY(-180deg);
}

What we just did was introduce CSS Grid to our cards. This being broken down:

  • display: grid on the card flipper allows to use CSS Grid to set positions for the contents of that container
  • grid-template: 1fr/1fr instructs our grid to have a 1 X 1 layout
  • grid-template-areas is used to name the areas of your template for convenience purposes(this is not necessarily needed)
  • grid-area defines the location of the cards(this is what finally stacks our cards on top of each other, since we placed them on the same area)

Now to combine Bootstrap 4 and our Flipping Cards container, we need to adjust our HTML:

<div class="container">
    <div class="row">
        <div class="col-md-4 card-container">
            <div class="card-flip">
                <div class="card front">
                    <!-- card content -->
                </div>
                <div class=" card back">
                    <!-- card content -->
                </div>
            </div>
        </div>
    </div>
</div>

By creating a .row and .col-md-* we can place as many Flipping Cards as we want, allowing them to flow on different rows and adjust on different screen sizes.

The .card is used to make our front and back sides look like cards. Then we can place contents inside the cards as we would usually do with normal cards.

Note: Since there are two cards in the same location, Card Overlay Images might not work exactly as intended. i.e. if the front of your card is an overlay and the contents of the back card are larger than the contents of the front, the height of both cards will be the height of the back side, meaning that the image will cover only the front side's original area.

Now to make our cards have the same height on larger devices, we need to make our .card-container use Grid as well:

.card-container {
    display: grid;
    perspective: 700px;
}

This wraps it all up! Hope you enjoyed this post. Please leave any suggestions or comments below.

See full code on CodePen.

Comments


  • Date T
    16 Jun 2020

    Thanks for sharing, just what I wanted!

  • Lili
    28 Jul 2020

    Thank you ! Very useful.

  • DJ
    11 Sep 2020

    Hey there, Nicolas, I love this elegant and super simple solution but when I went to implement it, I see the back of the card in resting state (prior to hovering) - in Mozilla Firefox only. I tried a few tricks suggested on StackOverflow before bothering you; adding a `transform: rotateY(0deg)` to the .front div, and adding -moz-backface-visibility: hidden; to the parent .card-flip div but nothing seemed to fix it. If you want to check it out, its about 2/3 the way down this page: https://kbmax.com/response?ind=heavy-equipment&amp;uc=engineer-to-order. It's the leanest solution I've found for this, just stuck on this last little thing...Thanks!

    • Nicolas Kadis
      14 Sep 2020

      Hi there DJ, I'm glad you found my solution useful. I've looked at your implementation and I would suggest to add a .card to the .front and .back divs, and also setting the z-index of .front to 1 and the z-index of .back to 0 (or any index you like keeping in mind that .back has to be a lower number. I hope you find this helpful :)

      • DJ
        23 Sep 2020

        Hey again, Nicolas, thanks for taking a look. Adding .card to .front and .back seemed to do the trick. I didn't seem to need the z-index. Thanks so much for everything!

        • Nicolas Kadis
          24 Sep 2020

          I'm happy to hear that worked out! You're welcome!

  • Chris
    21 Sep 2020

    Thank you very much! Exactly what I needed. I changed the mechanics slightly, because I need to trigger it by click: Instead of .card-container:hover .card-flip { transform: rotateY(180deg); } I use and set .rotated via script .card-flip.rotated { transform: rotateY(180deg); }

    • Nicolas Kadis
      21 Sep 2020

      Hi Chris, I'm happy to hear you found my solution helpful. If you're looking to do the same without any JavaScript, I've got a CodePen with a version where the cards are triggered via click. It uses checkboxes instead of JavaScript. Here's the link: https://codepen.io/nicolaskadis/full/bOLEEd

  • Arjan
    12 Nov 2020

    Did you notice that this effect doesn't work very well on Safari? It's fine on all Chrome, Firefox and Edge (all the decent browsers). Does anyone know how to make Safari play nice as well?

  • Arjan
    12 Nov 2020

    Fix for Safari: add -webkit-backface-visibility to the ".cardflip div" class, like so: .card-flip div { -webkit-backface-visibility: hidden; backface-visibility: hidden; transform-style: preserve-3d; }

Comment