Both of the answers posted here are good universal css flippers, but they donβt touch on the core of the question, βHow does Google do this?β The problem is that google minimizes and therefore confuses their code, which makes it difficult to say exactly what is happening, but with the help of the DOM inspector, you can get a pretty basic idea. This is an abstract:
- Create a div with "clone" that contains the front and back child divs but is hidden by default. Set its css transition property to ~ .5seconds so that any movement of it is animated.
- When the user clicks on the map in the grid, set the clone so that it is the same position / size, like a clicked map, copy the contents of the clicked map to the front child element and set it as visible
- Hide original clickable map with visibility: hidden
- At the moment, you now have a clone of the originally clicked card in the same place, but no one can tell
- Set the css for the top, left, height, width of the clone div to the pre-calculated sizes, centering on the screen, and also set the conversion: rotateY () of the front / rear children
- At this point, it seems that the div rises, flips and moves / changes to the center of the screen. The empty space is left behind because the original map is still there, but visibility: hidden allows it to take up space without showing its contents
- The click handler is configured so that when the user clicks outside the clone map, top, left, height, width, conversion: rotateY () css reset returns to the original values, which cause it to return back in place.
- Then the clone disappears again, and the original map becomes visible.
Demo: http://jsfiddle.net/jwhazel/AaU6v/11/
(Developed in Chrome may require 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('
source share