Designing a card flip animation featuring front and back faces without using absolute positioning

Looking to enhance my website with a new feature that incorporates the card-flipper schema found on David Walsh's site: https://davidwalsh.name/css-flip. The challenge arises from the fact that the content within my cards is dynamic, making the height unknown due to the responsive nature of the site. There is a footer positioned at the bottom of the page that must remain below this content area. However, utilizing absolute positioning causes the footer to display at the top as demonstrated in this codepen: https://codepen.io/anon/pen/ALJmGZ

Seeking suggestions for CSS hacks or modifications to eliminate the need for absolute positioning while maintaining the functionality of the card flip effect.

HTML:

<div class="flip-container" ontouchstart="this.classList.toggle('hover');">
  <div class="flipper">
    <div class="front">
      <span class="name">David Walsh</span>
    </div>
    <div class="back">
      <div class="back-logo"></div>
      <div class="back-title">@davidwalshblog</div>
      <p>Mozilla Web Developer, MooTools & jQuery Consultant, MooTools Core Developer, Javascript Fanatic, CSS Tinkerer, PHP Hacker, and web lover.</p>
    </div>
  </div>
  <footer>Here is my footer</footer>
</div>

CSS:

.flip-container {
  -webkit-perspective: 1000;
  -moz-perspective: 1000;
  -o-perspective: 1000;
  perspective: 1000;

    border: 1px solid #ccc;
}

    .flip-container:hover .flipper,  
  .flip-container.hover .flipper {
        -webkit-transform: rotateY(180deg);
        -moz-transform: rotateY(180deg);
    -o-transform: rotateY(180deg);
        transform: rotateY(180deg);
    }

.flip-container, .front, .back {
    width: 320PX;
    height: 427px;
}

.flipper {
    -webkit-transition: 0.6s;
    -webkit-transform-style: preserve-3D;

    -moz-transition: 0.6s;
    -moz-transform-style: preserve-3D;

  -O-transition: 0.6s;
    -o-transform-style: preserve-3D;

    transition: 0.6s;
    transform-style: preserve-3D;

    position: relative;
}

.front, .back {
    -webkit-backface-visibility: hidden;
    -moz-backface-visibility: hidden;
  -o-backface-visibility: hidden;
    backface-visibility: hidden;

    position: absolute;
    top: 0;
    left: 0;
}

.front {
    background: url(http://davidwalsh.name/demo/dwflip.jpg) 0 0 no-repeat;
    z-index: 2;
}

.back {
    -webkit-transform: rotateY(180DEG);
    -moz-transform: rotateY(180DEG);
  -O-transform: rotateY(180DEG);
    transform: rotateY(180DEG);

    background: #f8F8f8;
}

.front .name {
    font-size: 2em;
    display: INLINE-block;
    background: rgba(33, 33, 33, 0.9);
    color: #f8F8f8;
    font-family: Courier;
    padding: 5px 10px;
    border-radius: 5px;
    bottom: 60px;
    left: 25%;
    position: absolute;
    text-shadow: 0.1EM 0.1EM 0.05EM #333;

    -webkit-transform: rotate(-20deg);
    -moz-transform: rotate(-20deg);
  -O-transform: rotate(-20deg);
    transform: rotate(-20deg);
}

.back-logo {
    position: absolute;
    top: 40px;
    left: 90px;
    width: 160px;
    height: 117PX;
    background: url(http://davidwalsh.name/demo/logo.png) 0 0 no-repeat;
}

.back-title {
    font-weight: bold;
    color: #00304a;
    position: absolute;
    top: 180px;
    left: 0;
    right: 0;
    text-align: center;
    text-shadow: 0.1em 0.1em 0.05em #acd7e5;
    font-family: Courier;
    font-size: 2em;
}

.back p {
    position: absolute;
    bottom: 40px;
    left: 0;
    right: 0;
    text-align: center;
    padding: 0 20px;
  font-family: Arial;
  line-height: 2em;
}

footer {
  background:red;
}

Answer №1

Discovering a unique method to achieve this task without relying on position absolute, I utilized pure CSS with animations instead of transitions. By setting the height and width of elements to 0 at the 50% keyframe, the desired effect was achieved successfully. Feel free to explore the demonstration on Codepen: https://codepen.io/anon/pen/bwmkAo

Sass:

@keyframes no-show {
    0% {
        transform: rotateY(0deg);
        height: auto;
        width: 100%;
    }

    49% {
        height: auto;
        width: 100%;
    }

    50% {
        height: 0;
        width: 0;
    }

    100% {
        transform: rotateY(180deg);
        height: 0;
        width: 0;
    }
}

@keyframes show {
    0% {
        transform: rotateY(-180deg);
        height: 0;
        width: 0;
    }

    49% {
        height: 0;
        width: 0;
    }

    50% {
        height: auto;
        width: 100%;
    }

    100% {
        transform: rotateY(0deg);
        height: auto;
        width: 100%;
    }
}

.flip-container {
    border: 1px solid #ccc;
}

.flip-container, .front, .back {
    width: 320px;
}

.flipper {
    position: relative;
}

.front, .back {
    position: relative;
    perspective: 1000px;

    transform-style: preserve-3d;
    perspective-origin: top center;
    animation-duration: 2s;
    animation-timing-function: linear;
    transition-property: transform;
    animation-fill-mode: forwards;
    -webkit-animation-fill-mode: forwards;
    overflow: hidden;
}

.front {
    z-index: 2;

    transform: rotateY(0deg);
    animation-name: show;
    .flipper.active & {
        animation-name: no-show;
    }

    .inner {
        height: 300px;
        background: green;
    }
}

.back {
    transform: rotateY(-180deg);
    animation-name: no-show;

    .flipper.active & {
        animation-name: show;
    }

    .inner {
        height: 400px;
        background: blue;
    }
}

footer {
    background: red;
}

Answer №2

Today, I experimented with this concept, stumbling upon this question as my solution involves a small twist.

.flip-container {
  perspective: 1000;
}
.flipper {
  transform-style: preserve-3d;
  display: flex;
  align-items: stretch;
  width: 100%;
  transition: transform 0.6s;
  will-change: transform;
}
.flip-container:hover .flipper {
  transform: rotateY(180deg);
}
.front, .back {
  width: 100%;
  flex: 0 0 auto;
  backface-visibility: hidden;
}
.back {
  transform: rotateY(180deg);
  margin-left: -100%;
}

This approach works because items in a row can take the height of the tallest item in that row when using Flexbox. Customize the styles for .front and .back accordingly without specifying their height.

The catch here is that the shorter side may have rendering issues with its height if the other side expands post-rendering (like due to an image loading). It's okay if heights adjust due to window resizing, but it seems problematic when content loads suddenly. One workaround could be placing images within containers with fixed heights if you don't mind deviating from a pure CSS solution. Alternatively, waiting for the image to load before displaying the entire flip card could help, although this might not apply if you aren't using an img element.

Answer №3

Creating Flip Cards nowadays is easier with CSS Grid and without the need for absolute positioning. Check out this simple example:

body {
  background: #1339ac;
  padding: 50px;
}

.flipCard {
  perspective: 1000px;
}
.flipCard .boxes {
  display: grid;
  transition-duration: 0.6s;
  transition-timing-function: ease-in-out;
  transform-style: preserve-3d;
}
.flipCard .boxes .box {
  background: gold;
  padding: 1rem;
  border: 2px solid #000;
  /*---------*/
  grid-row: 1/2;
  grid-column: 1/2;
  -webkit-backface-visibility: hidden;
          backface-visibility: hidden;
}
.flipCard .boxes .box.front {
  transform: rotateX(0deg);
}
.flipCard .boxes .box.back {
  transform: rotateX(-180deg);
}
.flipCard:hover .boxes {
  transform: rotateX(-180deg);
}
<div class="flipCard">
  <div class="boxes">
    <div class="box front">
      <h2>Box 1</h2>
      <ul>
        <li>List Item 01</li>
        <li>List Item 02</li>
        <li>List Item 03</li>
      </ul>
    </div>
    <div class="box back">
      <h2>Box 2</h2>
      <ul>
        <li>List Item 01</li>
        <li>List Item 02</li>
        <li>List Item 03</li>
        <li>List Item 04</li>
        <li>List Item 05</li>
        <li>List Item 06</li>
      </ul>
    </div>
  </div>
</div>

Answer №4

Creating a similar effect to this one without using absolute positioning might be challenging.

To achieve this, you could use JavaScript to calculate the heights dynamically.

You can check out a basic example on CodePen: https://codepen.io/CourtDemone/pen/vXVbGQ

The concept involves moving the footer outside of the flip container and implementing some JavaScript logic like the following:

var heightFront, heightBack;

heightFront = $('.front').height();
heightBack = $('.back').height();

if(heightFront > heightBack){
  $('.flip-container').height(heightFront);
}else{
  $('.flip-container').height(heightBack);
}

Answer №5

I encountered a similar challenge as the one illustrated on the David Walsh blog, where I needed to implement a flip effect within a flex layout. It became evident that utilizing absolute positioning for flipping panels was not yielding the desired results.

To overcome this obstacle, I implemented the following:

  • Set relative positioning in the .flipper class
  • Defined a fixed height for the block with the .flipper class while allowing different height variations by specifying height: 15em separately
  • Assigned top: 0 for the front block and a negative value for the back block

Adjusting the values was necessary to create margins and spaces between elements. Instead of using hover effects, I opted for an onclick event to enhance the user experience, although both options are viable.

<!-- HTML -->
<p>three boxes on a flex basis with an onclick flip effect</p>
<div class='flexinl'>
    <div class='flip-container fronted hand' 
      onclick="this.swapClasses('fronted,backed');">
        <div class="flipper fli300">
            <div class='front c1'>
                <h1>This is front 1</h1>
            </div>
            <div class='back c2'>
                <h1>This is back 1</h1>
            </div>
        </div>
    </div>
    <div class='flip-container fronted hand' 
      onclick="this.swapClasses('fronted,backed');">
        <div class="flipper fli300">
            <div class='front c1'>
                <h1>This is front 2</h1>
            </div>
            <div class='back c2'>
                <h1>This is back 2</h1>
            </div>
        </div>
    </div>
    <div class='flip-container fronted hand' 
      onclick="this.swapClasses('fronted,backed');">
        <div class="flipper fli300">
            <div class='front c1'>
                <h1>This is front 3</h1>
            </div>
            <div class='back c2'>
                <h1>This is back 3</h1>
            </div>
        </div>
    </div>
</div>  

/* CSS */
.c1 {color:white; background-color:green}
.c2 {color:white; background-color:orange}
.hand { cursor: pointer; }

/* based on David Walsh Flipper */
.flip-container {
    perspective: 1000px;
    border: 1px dashed #a9a9a9;
    margin-bottom:1.5em;    
}
  /* flip the pane when has the backed */
.flip-container.backed .flipper {
    transform: rotateY(180deg);
}
.fli300 {height: 15em;}
.fli300 .front {
    height: 12em !important;
}
.fli300 .back {
    height: 12em !important;
    top: -15em;
}

/* flip speed goes here */
.flipper {
    transition: .4s;
    transform-style: preserve-3d;
    position: relative;    
}

/* hide back of pane during swap */
.flipper .front, .flipper .back {
    backface-visibility: hidden;
    position: relative;
    left: 0;
    height: 100%;
    padding: 1.5em;    
}

/* front pane, placed above back */
.flipper .front {
    z-index: -1;
    top: 0;
    /* for firefox 31 */
    transform: rotateY(0deg);
}

/* back, initially hidden pane */
.flipper .back {
    transform: rotateY(180deg);
}

/* some flex stuff */
.flexinl {  
    display: inline-flex; 
    flex-wrap: wrap;  
    justify-content: flex-start;
}
.flexinl > div {padding:0.2em}

/* javascript for swapping classes */

HTMLElement.prototype.swapClasses = function (dosclasses) {
    var clases = dosclasses.split(/\s*\,\s*/);
    var entra = clases[0];
    var sale = clases[1];
    if (this.classList.contains(sale)) {
        this.classList.remove(sale);
        this.classList.add(entra);
    } else {
        this.classList.remove(entra);
        this.classList.add(sale);
    }
    return this;
};

You can view the codepen demo here

Answer №6

You have the ability to make the container adjust to the height of its parent using the .front and .back classes and setting height: inherit;.
JSfiddle: https://jsfiddle.net/9q7xr4ef/

Code Snippet:

.flip-container {
  -webkit-perspective: 1000;
  -moz-perspective: 1000;
  -o-perspective: 1000;
  perspective: 1000;
  border: 1px solid #ccc;
}
.flip-container:hover .flipper,
.flip-container.hover .flipper {
  -webkit-transform: rotateY(180deg);
  -moz-transform: rotateY(180deg);
  -o-transform: rotateY(180deg);
  transform: rotateY(180deg);
}
.flip-container,
.front,
.back {
  width: 320px;
  height: 427px;
}
.flipper {
  -webkit-transition: 0.6s;
  -webkit-transform-style: preserve-3d;
  -moz-transition: 0.6s;
  -moz-transform-style: preserve-3d;
  -o-transition: 0.6s;
  -o-transform-style: preserve-3d;
  transition: 0.6s;
  transform-style: preserve-3d;
  position: relative;
  height: inherit;
}
.front,
.back {
  -webkit-backface-visibility: hidden;
  -moz-backface-visibility: hidden;
  -o-backface-visibility: hidden;
  backface-visibility: hidden;
  position: absolute;
  top: 0;
  left: 0;
}
.front {
  background: url(http://davidwalsh.name/demo/dwflip.jpg) 0 0 no-repeat;
  z-index: 2;
}
.back {
  -webkit-transform: rotateY(180deg);
  -moz-transform: rotateY(180deg);
  -o-transform: rotateY(180deg);
  transform: rotateY(180deg);
  background: #f8f8f8;
}
.front .name {
  font-size: 2em;
  display: inline-block;
  background: rgba(33, 33, 33, 0.9);
  color: #f8f8f8;
  font-family: Courier;
  padding: 5px 10px;
  border-radius: 5px;
  bottom: 60px;
  left: 25%;
  position: absolute;
  text-shadow: 0.1em 0.1em 0.05em #333;
  -webkit-transform: rotate(-20deg);
  -moz-transform: rotate(-20deg);
  -o-transform: rotate(-20deg);
  transform: rotate(-20deg);
}
.back-logo {
  position: absolute;
  top: 40px;
  left: 90px;
  width: 160px;
  height: 117px;
  background: url(http://davidwalsh.name/demo/logo.png) 0 0 no-repeat;
}
.back-title {
  font-weight: bold;
  color: #00304a;
  position: absolute;
  top: 180px;
  left: 0;
  right: 0;
  text-align: center;
  text-shadow: 0.1em 0.1em 0.05em #acd7e5;
  font-family: Courier;
  font-size: 2em;
}
.back p {
  position: absolute;
  bottom: 40px;
  left: 0;
  right: 0;
  text-align: center;
  padding: 0 20px;
  font-family: arial;
  line-height: 2em;
}
footer {
  background: red;
}
<div class="flip-container" ontouchstart="this.classList.toggle('hover');">
  <div class="flipper">
    <div class="front">
      <span class="name">David Walsh</span>
    </div>
    <div class="back">
      <div class="back-logo"></div>
      <div class="back-title">@davidwalshblog</div>
      <p>Mozilla Web Developer, MooTools & jQuery Consultant, MooTools Core Developer, Javascript Fanatic, CSS Tinkerer, PHP Hacker, and web lover.</p>
    </div>
  </div>
  <footer>Here is my footer</footer>
</div>

# 2, one child is relative:
JSfiddle: https://jsfiddle.net/9q7xr4ef/2/

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Restrict the Number of Columns in GridView

I am currently working with a gridview that displays product information. I'm trying to find a way to limit the description field so that only the first few lines are shown if it is too long, and also resize the image to fit into the image column whil ...

Constructing a comprehensive inventory is a skill that requires strategy

Can someone advise on the best way to create a list structure with one parent category and two subcategories, each containing three items? Would it be ideal to use a combination of span and two uls, or perhaps a mix of span, anchor tags, and ul elements? ...

Step-by-step guide to positioning an iframe with 'transform:scale' on the left side

Recently, I encountered an issue with an iframe in my project. Initially, without any 'transform:scale' css applied, it displayed on the top-left side of the div as expected. However, after adding -webkit-transform:scale(0.6,1); margin-left:0.0e ...

Can a CSS3 filter be utilized to transform gradient colors into solid colors?

I have an interesting scenario where I am using a -webkit-mask with a radial-gradient to create small dots on a background image. These dots are transparent, allowing the background image to show through. However, each dot has a gradient color within it. ...

Ensure the padding and margin are both set to 0 when using inline styles

As someone who is not a designer, I attempted to send an email from PHP. In order to do so, I took a template and converted all styles to inline. However, I am unsure of where to include the universal margin and padding style in the template. *{margin:0px ...

Having trouble getting my HTML file and CSS styles to render properly in Chrome

Currently, I am in the process of developing a website and facing challenges with displaying CSS properties accurately. Despite seeking input from friends and users, my HTML file is not rendering as expected within various browsers such as Chrome, Edge, an ...

Is there a way to set up a basic form on my website (cPanel based) that is only accessible during specific time frames?

Every week, I host a conference and I want to keep track of which participants are present. I want attendees to visit my website, input their name, and click "Enter". Then, I want their information to be saved in a database on my website. My website is man ...

storing information in HTML using Django

Recently, I have been learning about Django Rest and I am now trying to display some JSON data in HTML. The JSON data I have is: {'Resul': {'Period Start': '2017-01-01', 'Period End': '2017-12-12'}} When ...

Screen JSON data by applying filters

In my current project, I am working on extracting data from a JSON file and presenting it to the user in a way that allows them to input values that match the expected data. My goal is to show different sections of the screen at different times. The initi ...

Ways to halt a script entirely once its tag has been eliminated

I have a script from a page tracker website that runs periodically. Occasionally I need to restart the script from the beginning. To do this, I typically remove the script tag from the DOM and then re-append it. However, because the script utilizes setInt ...

Ways to enhance an image by zooming in when the user reaches a designated area on the webpage

I have implemented a feature where an image zooms in to letter L when the user scrolls on the page. However, I want this zoom effect to occur only when the user reaches a specific section of the site, rather than immediately when the image loads. In my exa ...

Ways to enable users to showcase the files they have uploaded

I've successfully implemented code for file uploading. When saving the uploaded file in the database, I retrieve the uploader's username from another database. Additionally, I have a page that displays all uploaded files, functioning perfectly. N ...

Textfield with autocomplete dropdown

I have a text field on my website that needs to work as an autocomplete box. I have included the following code in the "headerbar" section of my page: Find :<input type="text" class="input2" style="margin-bottom:0px;" id="customersearchfield"> < ...

Make the height of the input element equal to 100% of its parent

I am struggling with setting the height of input (type text) to fit 100% of its parent element (td). I attempted to individually adjust the height of each input using jQuery, but this method is time-consuming, especially since the site I am working on ha ...

Using a simulation to deactivate webpage elements and showcase the UpdateProgress control

I am currently attempting to disable certain page elements and display an update progress control in my application. In order to achieve this, I have applied a style sheet with the property filter: alpha(opacity=85); However, I encountered an error stati ...

Transforming the appearance of the menu element in Vue using transitions

In my Vue app, I have this SCSS code that I'm using to create a smooth transition effect from the left for a menu when the isVisible property is set to true. However, I am encountering an issue where the transition defined does not apply and the menu ...

Creating interactive labels in a histogram that update based on the user's input

Currently, I have operational code in place that takes input data and generates a histogram based on set thresholds. When the code is executed, the histogram changes dynamically as the threshold slider is adjusted. However, there seems to be an issue wit ...

Bootstrap 4 allows for the use of the d-lg-flex class to create a flexible column layout

I'm facing an issue with my table on smaller screens where some columns need to be hidden. Here's the code snippet I'm using: <table> <tr> <td>Normal 1</td> <td class="d-lg-flex d-none">hidden 1</t ...

Issue with ThreeJs: Difficulty loading separate images on top and bottom surfaces

I've been trying to place different textures on the top and bottom sides using Threejs to display unique images on each side. However, I'm encountering an issue where the same image is being displayed on both the top and bottom sides. Below is th ...

The erratic nature of Tailwind actions

Currently, I am immersed in a Livewire project and attempting to implement some Tailwind theme configurations. However, the process does not appear to be coherent whatsoever. Here is an excerpt of my Tailwind configuration: theme: { extend: { f ...