Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The Google card's "Flip and Grow" effect

I have been doing some research on how to create a flip and grow effect like Google card does (click on any card):

http://www.google.com/landing/now/#cards/restaurant-reservations

All resources I found is about flipping a card with front and back of same size but this is not what I'm looking for.

Any feedback will be hugely appreciated.

like image 667
emersonku Avatar asked Jul 01 '14 06:07

emersonku


2 Answers

Both of the answers posted here are good generic css flippers but they don't address the core of the question which is "how does Google do it?". The problem is that google minifies and therefore obfuscates their code which makes it tough to tell exactly whats going on but using a DOM inspector you can get a pretty basic idea. This is the abstract:

  • Build a "clone" div that contains a front and a back child div but is hidden by default. Set it's css transition property to ~.5seconds so that any move it makes will be animated.
  • When a user clicks on a card in the grid, set the clone so it's the same position/dimensions as the clicked card, copy the contents of the clicked card into the front child element and set it as visible
  • Hide the original clicked card with visibility:hidden
  • At this point you now have a clone of the originally clicked card in the exact same place but no one can tell
  • Set css for top, left, height, width of the clone div to precalculated dimensions centering in the screen while also setting transform:rotateY() of the front/back children
  • At this point it appears as if the div is lifting up, flipping around, and moving/resizing to the center of the screen. An empty spot is left behind because the original card is still there, but visibility:hidden allows it to take up space without showing its contents
  • A click handler is set up so that when the user clicks outside of the clone card, the top,left,height,width,transform:rotateY() css is reset back to the original values which make it fly back in place.
  • Then the clone is hidden again and the original card is made visible

Demo: http://jsfiddle.net/jwhazel/AaU6v/11/

(Developed in Chrome, may need some vendor prefixes for other browsers)

HTML


    <div class="cards">Generic Tile Card</div>

    <div id="cardClone">
        <div id="cloneFront">cardclone front</div>
        <div id="cloneBack">cardclone back</div>
    </div>

CSS


body {
    position: relative;
    font-family:Helvetica, Arial, Sans-serif;
    text-align:center;
}
.cards {
    margin:30px;
    width:200px;
    height:200px;
    background-color:#59A3FF;
    cursor:pointer;
    display:inline-block;
    overflow:hidden;
}
img {
    display:block;
    width:80%;
    height:auto;
    margin:0 auto
}
#cardClone {
    position:fixed;
    display:none;
    margin:30px;
    width:200px;
    height:200px;
    -webkit-transition:.6s;
    transition:.6s;
    -webkit-transform-style::preserve-3d;
    transform-style:preserve-3d;
    z-index:99;
    perspective: 1000px;
    -webkit-perspective: 1000px;
}
#cloneFront, #cloneBack {
    backface-visibility: hidden;
    width:100%;
    height:100%;
    position:absolute;
    -webkit-transition:.6s;
    transition:.6s;
    overflow:hidden;
}
#cloneFront {
    z-index:100;
    background-color:#59A3FF;
    transform: translatez(0);
}
#cloneBack {
    transform:rotateY(-180deg);
    z-index:101;
    background-color:#aaa;
}

Javascript


//Cache the clone since we have to select it a couple of times
$clone = $('#cardClone');

//Set a global for the card we just clicked so we can track it
$lastelement = "";

//Set up an object for last clicked element so we know where to return to on collapse
lastelement = {
    'top': 0,
        'left': 0,
        'width': 0,
        'height': 0
};

//Set a flag to determine the current flip state of our clone
cloneflipped = false;


//Bind a handler to the clone so we can detect when the transition is done
$('#cardClone').on("transitionend", function (e) {
    if (e.target === e.currentTarget) {
        if (e.originalEvent.propertyName == 'top') {

            //Toggle the clone state
            cloneflipped = !cloneflipped;

            //Detect if our clone has returned to the original position and then hide it
            if (!cloneflipped) {
                $($lastelement).css('opacity', 1);
                $($clone).hide();
            } else {
                //Need to dynamically alter contents of the clone rear AFTER it animates? Do it here
                //$('#cloneBack').html('hi');
            }
        }
    }
});


$(".cards").click(function () {
    if (!cloneflipped) {
        //Cache clicked card
        $lastelement = $(this);

        //Store position of this element for the return trip
        //[hack: subtract 30 due to the margin of .cards in this demo]
        var offset = $lastelement.offset();
        lastelement.top = offset.top - 30 - $(document).scrollTop();
        lastelement.left = offset.left - 30;
        lastelement.width = $lastelement.width();
        lastelement.height = $lastelement.height();

        //BONUS: lets check to see if the clicked card is further to the left or the right of the screen
        //This way we can make the animation rotate inwards toward the center, google doesn't do this
        var rotatefront = "rotateY(180deg)";
        var rotateback = "rotateY(0deg)";
        if ((lastelement.left + lastelement.width / 2) > $(window).width() / 2) {
            rotatefront = "rotateY(-180deg)";
            rotateback = "rotateY(-360deg)";
        }


        //Copy contents of the clicked card into the clones front card
        $clone.find('#cloneFront').html($lastelement.html());


        //Show the clone on top of the clicked card and hide the clicked card
        //[hack: using opacity for hiding here, visibility:hidden has a weird lag in win chrome]
        $clone.css({
            'display': 'block',
                'top': lastelement.top,
                'left': lastelement.left
        });
        $lastelement.css('opacity', 0);

        //Need to dynamically alter contents of the clone rear BEFORE it animates? Do it here
        //$('#cloneBack').html('hi');

        //Flip the card while centering it in the screen
        //[hack: we have to wait for the clone to finish drawing before calling the transform so we put it in a 100 millisecond settimeout callback]
        setTimeout(function () {
            $clone.css({
                'top': '40px',
                    'left': '40px',
                    'height': '400px',
                    'width': $(document).width() - 140 + 'px'
            });
            $clone.find('#cloneFront').css({
                'transform': rotatefront
            });
            $clone.find('#cloneBack').css({
                'transform': rotateback
            });
        }, 100);
    } else {
        $('body').click();
    }
});


//If user clicks outside of the flipped card, return to default state
$('body').click(function (e) {
    if (cloneflipped) {
        if (e.target === e.currentTarget) {
            //Reverse the animation
            $clone.css({
                'top': lastelement.top + 'px',
                    'left': lastelement.left + 'px',
                    'height': lastelement.height + 'px',
                    'width': lastelement.width + 'px'
            });
            $clone.find('#cloneFront').css({
                'transform': 'rotateY(0deg)'
            });
            $clone.find('#cloneBack').css({
                'transform': 'rotateY(-180deg)'
            });
        }
    }
});
like image 70
jwhazel Avatar answered Oct 17 '22 03:10

jwhazel


your code is here ! clickFLIPgrove

You can scale size of a div by css property called transform:scale(2,2); it will double the size of your element refer this link for all css effects: cssAnimation

I have created flip effect on hover:

hoverFLIP

html


  <div class="cards"></div>

css


  body{
    position: relative;
}
.cards{
    margin:30px;
    perspective: 500;
    -webkit-perspective: 500;
    -moz-perspective: 500;
    -ms-perspective: 500;
    -o-perspective: 500;
    width:200px;
    height:200px;
    background-color:#59A3FF;
    transform-style:preserve-3d;
    -webkit-transform-style:preserve-3d;
    -moz-transform-style:preserve-3d;
    -o-transform-style:preserve-3d;
    position:absolute;
    cursor:pointer;
    /* Animate the transitions */
    -webkit-transition:0.8s; text-align:center;
    -moz-transition:0.8s; text-align:center;
    -ms-transition:0.8s; text-align:center;
    -o-transition:0.8s; text-align:center;
    transition:0.8s; text-align:center;

}

.flip{
  transform:rotateY(180deg) scale(1.2,1.2);
  -webkit-transform:rotateY(180deg) scale(1.2,1.2);
  -moz-transform:rotateY(180deg);
  -o-transform:rotateY(180deg);
  -ms-transform:rotateY(180deg);
  background-color:#FF5959;

}

javascript(add Jquery 2.1.0)


  $(".cards").click(function(){
    $(this).toggleClass("flip"); 
});
like image 35
Suresh Karia Avatar answered Oct 17 '22 02:10

Suresh Karia