1. Web Design
  2. UX/UI
  3. UI Design

How to Recreate Apple TV’s Parallax Thumbnail Rollover Effect

In this tutorial we’ll continue exploring 3D Transforms, by building a 3D parallax rollover effect, inspired by Apple TV’s interface.
Scroll to top
6 min read

In my previous tutorial I showed you how to use CSS 3D Transforms to create an isometric grid layout. It was quite challenging, since a few browsers such as Firefox have slightly different approaches in regard to how they render elements on a three-dimensional plane. 

In this tutorial we’ll continue exploring 3D Transforms, by building a 3D parallax rollover effect, inspired by Apple TV’s interface. We’ll still be using Envato Elements as inspiration for our content; here’s what we’re working towards:

Please accept marketing cookies to load this content.

Hover over the thumbnail and move your cursor around; the thumbnail will lean according to the cursor position and the direction of movement.

Perspective: a Primer

As human beings our visibility is limited up to the vanishing horizon, and our binocular vision creates what we perceive as perspective. Perspective helps us interpret an object to be further away, rather than simply being smaller.

Please accept marketing cookies to load this content.

The isometric grid from the previous tutorial does not take “perspective” into account. The grid size–height and width–is actually retained. In reality we should be seeing the farthest side of the grid shrinking due to perspective.

In CSS, we can add perspective to 3D transformation through the perspective() function. It is worth noting that perspective() has to be added before other transform functions such as rotate() and translate() for it to take effect. It also requires a value defining the view distance relative to the element; whether the element should be viewed from afar or near.

Please accept marketing cookies to load this content.


1
#perspective {
2
    transform: perspective(600px) rotateX(60deg) rotateY(0deg) rotateZ(-45deg);
3
}

That’s how we render a 3D plane with CSS. Now let’s see how we can apply this to create a parallax effect. We’ll start with the HTML:

The HTML Markup

If you followed our previous tutorial thoroughly, you will find the HTML markup to be quite similar. Here we have a div with a class of ItemCard wrapping the name, the image, and the link pointing to one of the items on Envato Elements.

1
<div class="ItemCard">
2
	<a class="ItemCard__dest cover" href="https://elements.envato.com/items/type/fonts/campfire-stories-font-duo-DH6LQG" target="_blank"></a>
3
	<figure class="ItemCard__thumb">
4
		<img src="./images/001.jpg" height="340" width="510" alt="">
5
	</figure>
6
	<div class="ItemCard__layer cover"></div>
7
	<div class="ItemCard__summary cover">
8
		<span class="ItemCard__meta category">Fonts</span>
9
		<h2 class="ItemCard__title">Herbert Lemuel</h2>
10
		<address class="ItemCard__meta designer">August10</address>
11
	</div>
12
</div>

Add the above HTML markup from top to bottom.

The CSS

We begin by adding some reset styles which, in this case, set the element’s box-sizing to border-box, remove the figure element margin, and make the image fluid.

1
html {
2
  box-sizing: border-box;
3
}
4
*,
5
*:before,
6
*:after {
7
  box-sizing: inherit;
8
}
9
figure {
10
	margin: 0;
11
}
12
img {
13
	max-width: 100%;
14
	height: auto;
15
}

With that done, we add some styles to the ItemCard. Beyond the aesthetic rules such as border-radius and box-shadow, we define the element transition and transformation including the perspective() function.

1
.ItemCard {
2
    position:relative;
3
4
    display:flex;
5
    overflow:hidden;
6
    flex-direction:column;
7
8
    cursor:pointer;
9
10
    border-radius:6px;
11
    box-shadow:0 2px 10px rgba( 0,0,0,.3 );
12
13
    align-items:center;
14
15
    max-width: 510px;
16
    height: auto;
17
18
    transition: transform .5s cubic-bezier(.215, .61, .355, 1),
19
                box-shadow .5s cubic-bezier(.215, .61, .355, 1);
20
    transform: perspective( 600px ) translate3d( 0, 0, 0 );
21
}

For more information on what cubic-bezier() is doing here, check out Guy Routledge’s course:

Meta Styles

Next, we add styles the ItemCard child elements; the item name, the item author name, and the item category. Similarly, the styles define the these elements’ visibility, position, sizing, transitions, and transformations.

1
.ItemCard .cover {
2
  position: absolute;
3
  top: 0;
4
  left: 0;
5
  width: 100%;
6
  height: 100%;
7
}
8
.ItemCard__dest {
9
  z-index: 30;
10
  display: block;
11
}
12
.ItemCard__thumb {
13
  position: relative;
14
  z-index: 3;
15
  padding: 0;
16
  transition: transform .2s;
17
}
18
.ItemCard__thumb img {
19
  display: block;
20
  transition: box-shadow 0.2s;
21
}
22
.ItemCard__layer {
23
  z-index: 10;
24
  transition: opacity 1s cubic-bezier(0.215, 0.61, 0.355, 1);
25
  opacity: 0;
26
  background: linear-gradient(120deg, #9d50bb 0%, #4096ee 100%);
27
}
28
.ItemCard__summary {
29
  z-index: 20;
30
  padding: 25px;
31
  display: flex;
32
  flex-direction: column;
33
  transform: perspective(600px) translate3d(0, 100%, 0);
34
  text-align: center;
35
  color: #fff;
36
  justify-content: center;
37
}
38
.ItemCard__title {
39
  margin: 8px 0;
40
  font-weight: 900;
41
  transform: translate3d(0, 150px, 50px);
42
  text-transform: uppercase;
43
  color: #fff;
44
  font-size: 19px;
45
  line-height: 1.48;
46
}

3D Rendering

Add the following styles to make the child elements of the ItemCard and the .ItemCard__summary compliant with three-dimensional rendering.

1
/**

2
 * Preserve 3D elements for the descendants

3
 */
4
.ItemCard,
5
.ItemCard__summary {
6
  transform-style: preserve-3d;
7
  backface-visibility: hidden;
8
}

Hover

The ItemCard hover state styles define the box-shadow as well the Z axis of some of the child elements:

1
/**

2
 * Hover States

3
 */
4
.ItemCard:hover {
5
  box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
6
}
7
.ItemCard:hover .ItemCard__layer {
8
  opacity: .9;
9
}
10
.ItemCard:hover .ItemCard__title {
11
  transform: translate3d(0, 0, 50px);
12
}
13
.ItemCard:hover .ItemCard__meta.category {
14
  transform: translate3d(0, 0, 40px);
15
}
16
.ItemCard:hover .ItemCard__meta.designer {
17
  transition-delay: .05s;
18
  transform: translate3d(0, 0, 20px);
19
}

At this point, you’ll have something which resembles the following:

thumbnail image of one of items in Envato Elementsthumbnail image of one of items in Envato Elementsthumbnail image of one of items in Envato Elements
Initial and hover state styles

Parallax Effect With jQuery

We’re going to harness some jQuery here, so make sure you’re linking to jQuery somewhere from within your document. In CodePen add https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js as an external JavaScript path. 

The parallax effect is applied through two jQuery Events mousemove and mouseout. The mousemove event fires up when the cursor is moving over the target element; in this case,.ItemCard. The mouseout fires when the mouse cursor is already outside the target element.

1
$( document )
2
  .on( "mousemove", ".ItemCard", function( event ) {
3
4
  } )
5
  .on( "mouseout", ".ItemCard", function() {
6
7
  } );

During the mousemove event, we retrieve the mouse cursor coordinates, determine the ItemCard rotation, and apply these numbers by adding inline styles. During the mouseout event, we strip out the inline style so that the ItemCard returns to its initial position.

1
$( document )
2
  .on( "mousemove", ".ItemCard", function( event ) {
3
4
    /**

5
     * Half of the `ItemCard` width

6
     * @type {integer}

7
     */
8
    var halfW = ( this.clientWidth / 2 );
9
10
    /**

11
     * Half of the `ItemCard` height

12
     * @type {integer}

13
     */
14
    var halfH = ( this.clientHeight / 2 );
15
16
    /**

17
     * Mouse cursor X coordinate

18
     * @type {integer}

19
     */
20
    var coorX = ( halfW - ( event.pageX - this.offsetLeft ) );
21
22
    /**

23
     * Mouse cursor Y coordinate

24
     * @type {integer}

25
     */
26
    var coorY = ( halfH - ( event.pageY - this.offsetTop ) );
27
28
    /**

29
     * X Rotation degree of `ItemCard`

30
     * @type {integer}

31
     */
32
    var degX  = ( ( coorY / halfH ) * 10 ) + 'deg'; // max. degree = 10

33
34
    /**

35
     * Y Rotation degree of `ItemCard`

36
     * @type {integer}

37
     */
38
    var degY  = ( ( coorX / halfW ) * -10 ) + 'deg'; // max. degree = 10

39
40
    /**

41
     * Add the inline styles

42
     */
43
    $( this ).css( 'transform', function() {
44
45
        return 'perspective( 600px ) translate3d( 0, -2px, 0 ) scale(1.1) rotateX('+ degX +') rotateY('+ degY +')';
46
      } )
47
      .children( '.ItemCard__summary' )
48
        .css( 'transform', function() {
49
          return 'perspective( 600px ) translate3d( 0, 0, 0 ) rotateX('+ degX +') rotateY('+ degY +')';
50
        } );
51
  } )
52
  .on( "mouseout", ".ItemCard", function() {
53
54
      /**

55
       * Remove the inline styles

56
       */
57
      $( this ).removeAttr( 'style' )
58
        .children( '.ItemCard__summary' )
59
          .removeAttr( 'style' );
60
  } );

And that’s a wrap.

Wrapping Up

In this tutorial we learned how to leverage 3D transformations to build a 3D parallax effect inspired by Apple TV.

Please accept marketing cookies to load this content.

Bear in mind, this effect will not work well on touch-enabled devices, so you’ll need to consider some kind of fallback, possibly with Touch Events to replicate the parallax effect–I will leave that on the table for you to tackle!

Useful Resources