How to implement a flip effect using Anuglar 2 animations?
14,918
Solution 1
this demo using animation in Angular
import { Component, OnInit, trigger, state, style, transition, animate } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<div class="tp-wrapper">
<div class="tp-box" (click)="toggleFlip()" [@flipState]="flip">
<div class="tp-box__side tp-box__front">Front
</div>
<div class="tp-box__side tp-box__back">Back
</div>
</div>
</div>
`,
styles: [
`
.tp-wrapper {
perspective: 800px;
}
.tp-box {
position: relative;
width: 200px;
height: 100px;
margin: 3rem auto;
transform-style: preserve-3d;
transition: transform 1s;
}
.tp-box__side {
width: 100%;
height: 100%;
position: absolute;
backface-visibility: hidden;
color: #fff;
text-align: center;
line-height: 100px;
font-size: 24px;
font-weight: 700;
cursor: pointer;
user-select: none;
}
.tp-box__front {
background: #f30d36;
}
.tp-box__back {
background: #23262d;
transform: rotateY(179.9deg);
}
`
],
animations: [
trigger('flipState', [
state('active', style({
transform: 'rotateY(179.9deg)'
})),
state('inactive', style({
transform: 'rotateY(0)'
})),
transition('active => inactive', animate('500ms ease-out')),
transition('inactive => active', animate('500ms ease-in'))
])
]
})
export class AppComponent {
flip: string = 'inactive';
constructor() {}
toggleFlip() {
this.flip = (this.flip == 'inactive') ? 'active' : 'inactive';
}
}
Online demo: https://plnkr.co/edit/RZ1v9M?p=preview
Solution 2
This works great in Chrome, but in Safari/Firefox/Opera the flipped side content shows through (in reverse) when the front side is visible, and vice-versa, but you just need to add the browser specific backface-visibility styles.
So replace this:
backface-visibility: hidden;
with this:
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-o-backface-visibility: hidden;
backface-visibility: hidden;
Then it displays in all browsers correctly.
![Tomasz Cysewski](https://lh3.googleusercontent.com/-XTmxbnXqVYU/AAAAAAAAAAI/AAAAAAAAAGA/_s1Zik4hqa4/photo.jpg?sz=256)
Author by
Tomasz Cysewski
Updated on June 30, 2022Comments
-
Tomasz Cysewski almost 2 years
I have been using pure css flip of cards in my project but this solution is not proper one. Can somebody present a flip in angular 2 on click of a button? I have found one in angularjs https://codepen.io/Zbeyer/pen/oXQrZg
<div ng-app="cardFlipper" ng-controller="AppController"> <h1>Card Flipping AngularJS</h1> <div class="flip-container"> <div class="flipper" ng-click="flipCard()" ng-class="{'flipToFront':isCardRevealed, 'flipToBack':!isCardRevealed}"> <div class="back" ng-class="{'face-hidden':hideBackFace}"> </div> <div class="front" ng-class="{'face-hidden':!hideBackFace}"> <h1>{{currentCard.title | uppercase}}</h1> <p ng-if="currentCard.icon">{{currentCard.icon}}</p> <br ng-if="currentCard.icon" /> <img ng-if="currentCard.imageUrl" src="{{currentCard.imageUrl}}" alt="currentCard.imageAlt" /> <p>{{currentCard.description}}</p> </div> </div> </div> <footer> <div ng-if="currentCard && currentCard.source"> <a ng-href="{{currentCard.source}}" target="_blank">Source</a> </div> </footer> <br /> <br /> </div> <style> /* CARD DIMENSIONS */ @width: 19em; @height: 27em; @shadow:1em 1em 2em #111111; /* MIXINS */ .box-shadow (@string:@shadow) { -webkit-box-shadow: @string; -moz-box-shadow: @string; box-shadow: @string; } .box-sizing(@sizing:border-box) { -webkit-box-sizing: @sizing; -moz-box-sizing: @sizing; box-sizing: @sizing; } .border-radius (@radius: 0.5em) { -webkit-border-radius: @radius; -moz-border-radius: @radius; border-radius: @radius; } .top-perspective() { /*perspective*/ -webkit-perspective:1000; -moz-perspective:1000; -ms-perspective:1000; -o-perspective:1000; perspective:1000; } .flipped-transform-back () { /*transform*/ -webkit-transform:rotateY(180deg); -moz-transform:rotateY(180deg); -ms-transform:rotateY(180deg); -o-transform:rotateY(180deg); transform:rotateY(180deg); } .flipped-transform-front { -webkit-transform: rotateY(0deg); -moz-transform: rotateY(0deg); -o-transform: rotateY(0deg); -ms-transform: rotateY(0deg); transform: rotateY(0deg); } .flipper-transform(@transition: 0.4s) { -webkit-transform-style: preserve-3d; -moz-transform-style: preserve-3d; -o-transform-style: preserve-3d; -ms-transform-style: preserve-3d; transform-style: preserve-3d; -webkit-transition: @transition; -moz-transition: @transition; -o-transition: @transition; -ms-transition: @transition; transition: @transition; } .back-face-should-be-hidden() { -webkit-backface-visibility: hidden; -moz-backface-visibility: hidden; -ms-backface-visibility: hidden; backface-visibility: hidden; } /* STYLE SHEET */ body { font-family: "myriad-pro", sans-serif; font-size:100%; text-align:center; color:#D1D1D1; padding: 0; background-color:#333333; margin:0 auto; padding: 0; } footer { text-align:center; padding:1em; a { font-size:1em; color:RGB(255, 208, 128); } } .flip-container { display:block; margin:0 auto; width: @width * 1.0; height: @height *1.0; } .flipToFront { .flipped-transform-front(); } .flipToBack { .flipped-transform-back(); } /* flip speed goes here */ .flipper { .top-perspective(); .flipper-transform(); width:100%; height:100%; position:relative; } .flip-container, .front, .back { .back-face-should-be-hidden(); text-align:center; color:#333333; padding: 0.25em; h1, h2, h3, a { font-size: 1.25em; } } .face-hidden { /* .face-should-be-hidden(); */ } .front, .back { /* hide back of pane during swap */ overflow:scroll; display:inline-block; /* Card overlay eachother */ position: absolute; top: 0; left: 0; /* Make Pretty */ .box-sizing(); .border-radius(); .box-shadow(); width:100%; height:100%; } /* front pane, placed above back */ .front { text-align:center; z-index: 2; background-color:#FEFEFE; .flipped-transform-front (); .box-sizing(); border:0.5em solid #FEFEFE; img { width:100%; margin: 0 auto; height:auto; .border-radius(); } } /* back, initially hidden pane */ .back { background-color:#EBEBEB; .flipped-transform-back (); background-image: url('http://subtlepatterns.com/patterns/upfeathers.png'); background-position: center; background-repeat: repeat; .box-sizing(); border:1em solid #FEFEFE; } /* Media Queries */ /* @highdensity: ~"only screen and (-webkit-min-device-pixel-ratio: 1.5)", ~"only screen and (min--moz-device-pixel-ratio: 1.5)", ~"only screen and (-o-min-device-pixel-ratio: 3/2)", ~"only screen and (min-device-pixel-ratio: 1.5)"; */ @mobile: ~"only screen and (max-width: 34em)"; @tablet: ~"only screen and (min-width: 34em) and (max-width: 55em)"; @desktop: ~"only screen and (min-width: 55em)"; @media @mobile { h1, h2, h3 { font-size: 1.25em; } .flip-container, .front, .back { width: @width * 1.0; height: @height *1.0; } } /* @media @tablet { .flip-container, .front, .back { width: @width * 1.25; height: @height *1.25; h1, h2, h3 { font-size: 1.75em; } } } @media @desktop { .flip-container, .front, .back { width: @width * 1.5; height: @height *1.5; } }*/ <script> angular.module('cardFlipper', []) .controller('AppController', ['$scope', '$interval', function($scope, $interval) { $scope.cards = [ { title: "escheresque-dark", icon:"", imageUrl:"http://subtlepatterns.com/patterns/escheresque_ste.png", description:"Sublte Pattern Source image below...", source: "http://subtlepatterns.com/escheresque-dark/" }, { title: "dark sharp edges", icon:"", imageUrl:"http://subtlepatterns.com/patterns/footer_lodyas.png", description:"Sublte Pattern Source image below...", source: "http://subtlepatterns.com/dark-sharp-edges/" }, { title: "Grey Washed Wall", icon:"", imageUrl:"http://subtlepatterns.com/patterns/grey_wash_wall.png", description:"Sublte Pattern Source image below...", source: "http://subtlepatterns.com/grey-washed-wall/" } ]; $scope.currentCard = {}; $scope.isCardRevealed = false; $scope.flipCard = function() { $scope.isCardRevealed = !$scope.isCardRevealed; if($scope.isCardRevealed) { $scope.generateCard(); } else { $scope.currentCard = {}; /* setTimeout(function() { // $scope.isBackHidden = !$scope.isCardRevealed; }, 0.1 * 1000); */ } /* */ } $scope.generateCard = function() { $scope.currentCard = {}; var index = Math.floor((Math.random() * $scope.cards.length) + 0); $scope.currentCard = $scope.cards[index]; } }]); </script>
Can somebody turn it into angular2 or implement something different?
-
Gustavo over 6 yearsIt's not working on Mozzila, how can I make it work?
-
Malindu over 6 yearsfor me, there is an odd behavior! stackblitz.com/edit/angular-card-flip. Could u please look into this?
-
Malindu over 6 yearsChecked it on Chrome, Safari, Firefox. Seems to like having a problem with Firefox.
-
Malindu over 6 yearsTried @stephen-r-smith answer but still no luck.
-
Roger over 5 years@Warapitiya Thanks for the link to stackblitz.com/edit/angular-card-flip. I made some minor style changes and it worked great for me! Tested fine on Chrome, Edge and Firefox v.61.0.2.
-
Roger over 5 yearsThis looks very similar, if not identical, to this example: stackblitz.com/edit/angular-card-flip, which works great for me (the Plunkr refuses to run).
-
Pooja Bansal over 5 yearsStill not able to flip it right in IE11. Facing same error while flipping and it shows reverse few of front box.