Published Feb 12, 2015Last updated Mar 14, 2017

Building a flipper using React JS and LESS CSS

Building a flipper using React JS and LESS CSS

Today, I'm going to explain how to create a flipping tile using CSS3 animations and React JS. If you've never used React JS, you're missing out. You can check it out here. I'm going to be using LESS CSS for some of the more advanced CSS because it allows us to completely ignore vendor prefixes through the use of LESS mixins. If you've never used LESS CSS either, I suggest you read up on it here. It's definitely worth picking up a CSS preprocessor even if it's not LESS.

I'm going to break the article down into two sections: the React section, in which I'll discuss what each of the various classes do and are responsible for; and the LESS CSS section, where I'll go over each of the various CSS classes and how they animate the flipper.

React

There are four classes that I'll go over: App, Flipper, Front, and Back.

App

var App = React.createClass({
  getInitialState: function() {
    return {
      flipped: false
    };
  },

  flip: function() {
    this.setState({ flipped: !this.state.flipped });
  },

  render: function() {
    return <div>
      <Flipper flipped={this.state.flipped} orientation="horizontal" />
      <Flipper flipped={this.state.flipped} orientation="vertical" />
            
      <div className="button-container">
        <button onClick={this.flip}>Flip!</button>
      </div>
    </div>;
  }
});

The App class is responsible for rendering most of the application, including various example Flippers and the button used to start the flip animation.

The getInitialState method sets up the App's state so that the tiles are not flipped by default. The flip method inverts the flipped state property, and the render method actually draws the application. In it, we're rendering two Flippers: one to flip horizontally and the other to flip vertically. There's also a button which is used to trigger the flip animation.

Flipper

var Flipper = React.createClass({
  render: function() {
    return <div className={"flipper-container " + this.props.orientation}>
      <div className={"flipper" + (this.props.flipped ? " flipped" : "")}>
        <Front>the front!</Front>
        <Back>the back!</Back>
      </div>
    </div>;
  }
});

The Flipper class is responsible for drawing the various divs and setting each of the classes used in the animation to flip from front to back. You'll see in the render method that there are also two more classes referenced: Front and Back. These classes contain what's shown on the front of the tile in the unflipped state, and what's on the back, which is shown when the tile is flipped.

Front and Back

var Front = React.createClass({
  render: function() {
    return <div className="front tile">{this.props.children}</div>;
  }
});
      
var Back = React.createClass({
  render: function() {
    return <div className="back tile">{this.props.children}</div>;
  }
});

The Front and Back classes are responsible for showing the appropriate content based on the flipped status of the parent Flipper class. The two classes are practically identical, with only a single class name separating the two, but I felt that they should be separated for readability's sake.

The children prop is a special prop which contains the child content of the class. When we're rendering each of the classes in the Flipper class above, you'll see the content for the two classes to be "the front!" and "the back!", respectively. That content gets placed in the children prop, which we're rendering in each of the tile classes render methods.

CSS

.flipper-container {
  float:left;
  width:250px;
  height:250px;
  margin-right:15px;
  display:block; .perspective;
        
  span {
    color:white;
  }
  
  >div.flipper {
    float:left;
    width:100%;
    height:100%;
    position:relative;
    .transform-style(preserve-3d);

    .front, .back {
      float:left;
      display:block;	
      width:100%;
      height:100%;
      .backface-visibility-hidden;
      position:absolute;
      top:0;
      left:0;
      .transform-style(preserve-3d);
      .transition(-webkit-transform ease 500ms);
      .transition(transform ease 500ms);
    }
          
    .front {
      z-index:2;
      background:#19489E;
              
      /* front tile styles go here! */
    }
          
    .back {
      background:#9E1919;
      
      /* back tile styles go here! */
    }
  }
}
      
.flipper-container.horizontal {
  .front { .transform(rotateY(0deg)); }
  .back { .transform(rotateY(-180deg)); }
        
  div.flipper.flipped {
    .front { .transform(rotateY(180deg)); }
    .back { .transform(rotateY(0deg)); }
  }
}
      
.flipper-container.vertical {
  .front { .transform(rotateX(0deg)); }
  .back { .transform(rotateX(-180deg)); }
        
  div.flipper.flipped {
    .front { .transform(rotateX(180deg)); }
    .back { .transform(rotateX(0deg)); }
  }
}

I've left out a bunch of the vendor-specific CSS rules for brevity's sake. The demo page has the full CSS rules to make the flipper work in all browsers, though, so if you need to see them, check it out.

There are a couple of fancy CSS rules that are in play here. I'll go through them all and describe what they're doing.

  • Transform-style
    The transform-style rule unsurprisingly indicates a style for the transform. In this example, we're only interested in the preserve-3d value, which indicates that any nested elements should preserve their rendering style in the third dimension. It means nothing without the transform CSS rule, which we're also using. This is what gives the illusion of the tile flipping. Without it, the tile would appear to shrink and grow instead of flipping in 3D.

  • Perspective
    This defines where the orientation and distance the viewer has of the 3D transformation. That sounds a little strange, but basically, it defines the number of pixels the rendered element is from the view.

  • Backface-visibility
    This property indicates the visibility status of the reverse side of elements. This makes no sense for static elements on a page, but in our case, it's important to hide the reverse side so we don't see a flipped version of the tile. In our example, the text "the front!" is printed on both the front and back of the tile. If we set this property to hidden, only the front side is visible.

Conclusion

And that's it! Thanks for reading. Once again, if you'd like to view these flip tiles in action, you can take a look at the demo page here.