3d Animated Mockup
November 12, 2014 | 15 Feedbacks

3D Animated Mockup

A simple template to showcase your application features through a smooth 3d animation, powered by CSS and jQuery.
Browser support
  • ie
  • Chrome
  • Firefox
  • Safari
  • Opera

With CSS 3D transformations supported by most modern browsers nowadays, we can enrich our web projects with powerful animations, and be confident most users will enjoy the full experience. Today’s template is just an example of how to turn a flat app screen into a 3D mockup, and animate it. We also integrated a popular resource, Points of Interest.

Inspiration came from Prismic.io.

Creating the structure

The HTML is structured in 2 main <div> elements (.cd-product-intro and .cd-product-mockup) – the first containing the product intro (title, action buttons..) and the second the mockup (and the points of interest) – wrapped inside a section.cd-product.

Two additional <div> elements (.cd-3d-right-side and the .cd-3d-bottom-side) have been used to create the 3d sides of the mockup, while the .cd-product-mockup::before pseudo-element has been used to create the shadow.

Adding style

On small devices the CSS is pretty straightforward (you can give a look at the code for more details/comments).
On desktop devices (viewport width more than 1170px) we assigned a position: absolute and width: 50% to the .cd-product-intro and set left: 0 in order to place it on the left side of the screen.
One note: we have been using the .cd-product-intro::before pseudo-element in order  to detect the current CSS Media Query in jQuery: the trick is done assigning different content values at different CSS Media Queries (for additional details,  you can check this article by Dudley Storey).

For the .cd-product-mockup, we set width: 450px and margin: 0 auto to put it in the centre of its container .cd-product, then rotated it using CSS 3D transformations:

The transform-style: preserve-3d assures that also .cd-3d-right-side and .cd-3d-bottom-side are positioned in the 3D-space (and not flattened in the plane, as it is by default).
In order to create the 3D sides effect, we set the mockup image as backgorund-image for both .cd-3d-right-side and .cd-3d-bottom-side,  and assigned them an additional CSS rotation (rotateX or rotateY according to the side):

For the mockup shadow, we used the .cd-product-mockup::before pseudo-element. We started applying the blur() filter to it;  this CSS property is not supported in Firefox 33 (and below) and in Internet Explorer 11 (and below). While this can be fixed in Firefox using an SVG filter,  there’s not an easy fix for IE. So we abandoned the blur() property and came out with a trick based on the box-shadow: we assigned a width: 0 and played with the blur radius and the spread radius to achieve a realistic effect.

One note: since in IE11 (and below) the transform-style: preserve-3d is not supported, you won’t see the 3D sides of of the mockup.

When user clicks the Start button, we add the .is-product-tour class to the .cd-product element: a translateX(-50%) is assigned to the .cd-product-intro and a translateX(0) to the .cd-product-tourCSS3 transitions to the transform and opacity values have been added in order to achieve the smooth animation.

Events handling

We used jQuery to add/remove classes (.is-product-tour class to the .cd-product when user clicks the start button, .is-open class to the .cd-single-point to show/hide point of interest).


May 25, 2015
  • Fixed bug on Chrome 43.0.2357.65
Nov 12, 2014
  • Resource released by CodyHouse

Claudia Romano

Web developer, fan of The Big Bang Theory and good food. Co-founder of CodyHouse and Nucleo. You can follow her on Twitter.

  • hey_dude_2323


  • Deryck Henson

    As usual, Claudia goin hard.

  • Get Bowtied


  • CameronJRoe


  • http://camgould.com/ Cam

    Nice. I love the depth on the rotated view of the screen elements :)

  • Chu Quang Tú

    Very cool. This worth for bookmarking. Thank you guys so much.


    Bene grazia Claudia!

  • hungltmed
  • Ciccio Balanza


  • Pishko Pishkof

    Thank you very much for this! Although, I had to rewrite 95% of the JS to be able to have this effect on multiple elements on the same page.

  • Kunal Bhardwaj


  • http://cviproductions.com Raphael

    Hello there. Can you please tell me how can i move the points of interest?
    And after that can you tell me how can i add more points of interest ?

    • http://codyhouse.co Claudia Romano

      Hi Raphael, you may try changing the top/bottom/left/right values of the .cd-single-point list items. To create a new one, add a li.cd-single-point to the ul.cd-points-container. Hope this helps!

  • http://www.halilyayic.com Halil İ. Yayıcı

    How to multiple mockup in one page and with small js code?

    I try this codes but not working except the first :/

    // Mock-Up
    $(‘#cd-start’).on(‘click’, function(event){
    var mq = window.getComputedStyle(document.querySelector(‘.cd-product-intro’), ‘::before’).getPropertyValue(‘content’).replace(/”/g, “”).replace(/’/g, “”);
    if(mq == ‘mobile’) {
    $(‘body,html’).animate({‘scrollTop': $($(this).attr(‘href’)).offset().top }, 200);
    } else {
    $(this).closest(‘.cd-product’).addClass(‘is-product-tour’).one(‘webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend’, function(){
    $(this).closest(‘.cd-product’).children(‘.cd-points-container’).addClass(‘points-enlarged’).one(‘webkitAnimationEnd oanimationend msAnimationEnd animationend’, function(){
    $(‘.cd-close-product-tour’).on(‘click’, function(){
    $(this).closest(‘.cd-product’).children(‘.cd-points-container’).removeClass(‘points-enlarged points-pulsing’);

  • http://www.i9algo.com.br/ I9 Algo

    Possible improvements to work with z-index:

    var selectedPoint = null;
    //open interest point description
    $(‘.cd-single-point’).children(‘a’).on(‘click’, function(){
    if (selectedPoint != null) {
    selectedPoint.css(“z-index”, “0”);
    selectedPoint = $(this).parent(‘li’);
    if( selectedPoint.hasClass(‘is-open’) ) {
    selectedPoint.css(“z-index”, “0”);
    } else {
    selectedPoint.css(“z-index”, “100”);
    //close interest point description
    $(‘.cd-close-info’).on(‘click’, function(event){

    //on desktop, switch from product intro div to product mockup div
    $(‘#cd-start’).on(‘click’, function(event){
    //detect the CSS media query using .cd-product-intro::before content value
    var mq = window.getComputedStyle(document.querySelector(‘.cd-product-intro’), ‘::before’).getPropertyValue(‘content’).replace(/”/g, “”).replace(/’/g, “”);
    if(mq == ‘mobile’) {
    $(‘body,html’).animate({‘scrollTop': $($(this).attr(‘href’)).offset().top }, 200);
    } else {
    $(‘.cd-product’).addClass(‘is-product-tour’).one(‘webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend’, function(){
    $(‘.cd-points-container’).addClass(‘points-enlarged’).one(‘webkitAnimationEnd oanimationend msAnimationEnd animationend’, function(){
    //on desktop, switch from product mockup div to product intro div
    $(‘.cd-close-product-tour’).on(‘click’, function(){
    $(‘.cd-points-container’).removeClass(‘points-enlarged points-pulsing’);