Custom Page Transitions (Part 2)


In Part 1 we used the Animate.css library of CSS animations as transitions for jQuery Mobile (jQM) pages, popups, and dialogs.  In Part 2, we will write our own KeyFrame animation CSS in order to have a unique/one-of-a-kind transition.

You will remember from last time, that to use a CSS transition with jQM, we create a class name for the transition and point that class at a named CSS animation. We can use different animations for the page entering, leaving, and the 2 reverse directions. An animation in CSS is created by defining a set of transforms at various points during the transition duration called keyFrames. Each KeyFrame’s time is defined as a percentage of the animation duration, so the simplest animations can be defined with only 2 KeyFrames: 0% – start transform, and 100% – end transform.  The browser is responsible for figuring out how to animate the transform values between the KeyFrames.

Example 1 – A Simple Slide In/Out Animation

Lets start simple and define an animation that slides the page in from 50% of its width on the left, and slides out 50% of its width on the right.  To achieve this, for the IN animation we need to setup a start KeyFrame with an X translation of –50% and an end X translation of 0; and for the OUT animation we need to setup a start KeyFrame with an X translation of 0 and an end X translation of 50% (we will leave reverse animations to the full example later)

IN animation

@-webkit-keyframes simpleSlide {
  0% {
    -webkit-transform:       translateX(-50%);
    -moz-transform:          translateX(-50%);
    -ms-transform:           translateX(-50%);
    transform:               translateX(-50%);
  }
  100% {
    -webkit-transform:       translateX(0);
    -moz-transform:          translateX(0);
    -ms-transform:           translateX(0);
    transform:               translateX(0);
  }
}
@keyframes simpleSlide {
  0% {
    -webkit-transform:       translateX(-50%);
    -moz-transform:          translateX(-50%);
    -ms-transform:           translateX(-50%);
    transform:               translateX(-50%);
  }
  100% {
    -webkit-transform:       translateX(0);
    -moz-transform:          translateX(0);
    -ms-transform:           translateX(0);
    transform:               translateX(0);
  }
}

OUT animation

@-webkit-keyframes simpleSlideOut {
  0% {
    -webkit-transform:       translateX(0);
    -moz-transform:          translateX(0);
    -ms-transform:           translateX(0);
    transform:               translateX(0);
  }
  100% {
    -webkit-transform:       translateX(50%);
    -moz-transform:          translateX(50%);
    -ms-transform:           translateX(50%);
    transform:               translateX(50%);
  }
}
@keyframes simpleSlideOut {
  0% {
    -webkit-transform:       translateX(0);
    -moz-transform:          translateX(0);
    -ms-transform:           translateX(0);
    transform:               translateX(0);
  }
  100% {
    -webkit-transform:       translateX(50%);
    -moz-transform:          translateX(50%);
    -ms-transform:           translateX(50%);
    transform:               translateX(50%);
  }
}

In this example we have named the animations simpleSlide and simpleSlideOut, so to use them, we create a class called simpleSlideTrans and assign the in and out animations.

.simpleSlideTrans.in {
    -webkit-animation-name:            simpleSlide;
    -moz-animation-name:               simpleSlide;
    animation-name:                    simpleSlide;
    -webkit-animation-timing-function: ease-out;
    -moz-animation-timing-function:    ease-out;
    animation-timing-function:         ease-out;
    -webkit-animation-duration:        900ms;
    -moz-animation-duration:           900ms;
    animation-duration:                900ms;
}
.simpleSlideTrans.out {
    -webkit-animation-name:            simpleSlideOut;
    -moz-animation-name:               simpleSlideOut;
    animation-name:                    simpleSlideOut;
    -webkit-animation-timing-function: ease-out;
    -moz-animation-timing-function:    ease-out;
    animation-timing-function:         ease-out;
    -webkit-animation-duration:        900ms;
    -moz-animation-duration:           900ms;
    animation-duration:                900ms;
}

Here is a Demo of this simple animation.

For more complex animations, we can define additional KeyFrames during the duration of the animation, we can animate opacity to create fades, we can animate 3d transform attributes such as translations along the Z-axis and rotations on X, Y, and Z axes, etc. So lets create a complex 3d animation for the in, out, and reverse directions.

Example 2 – A Complex 3d Animation

For this more complex animation I will remove all the vendor prefixed CSS attributes in the following code blocks so that it is easier to read. The linked demo will include the full CSS. Here is the IN animation:

@keyframes sideTwist {
  0% {
    transform-style:  preserve-3d;
    transform: perspective(800px) translate3d(-50%, 0px, -300px) rotateX(0deg) rotateY(30deg) rotateZ(50deg);
    transform-origin: 0 100%;
    opacity: 0.4;
  }
  40% {
    transform: perspective(800px) translate3d(-30%, 0px, 30px) rotateX(40deg) rotateY(10deg) rotateZ(-10deg);
    opacity: 0.7;
  }
  60% {
    transform: perspective(800px) translate3d(-20%, 0px, 0px) rotateX(50deg) rotateY(0deg) rotateZ(0deg);
    transform-origin: 50% 0;
    opacity: 0.8;
  }
  100% {
    transform: perspective(800px) translate3d(0,0,0) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
    opacity: 1;
  }
}

The new animation is called sideTwist. The transform-style property is set to preserve-3d so that all child elements of the page follow the 3d transforms.  In order to have a 3d transform, we must define a perspective which tells the browser how far above the object we are.  Transform-origin tells the transform where on the DOM element to center itself.  The main property is transform which can take many values that define translations, scaling, rotation, skew, etc. You can visit this CSS 3d Tranfom Playground to see how the various values affect an element.

For our animation we have defined 4 KeyFrames:

  • We start partially faded out (opacity of 0.4), translated 50% to the left and 300px away from us, rotated 30 degrees on the Y-axis and 50 degrees on the Z-axis. Our transform-origin is at the bottom left.
  • At 40% we have animated to an opacity of 0.7, 30% to the left, 30px away from us, rotated 40 degrees on the X-axis, 10 degrees on the Y-axis and –10 degrees on the Z-axis.
  • At 60% we have animated to an opacity of 0.8, 20% to the left and rotated 50 degrees on the X-axis; no more rotation in Y or Z axes. The transform-origin is now at the center top.
  • Finally we end up with no more translation or rotation and fully faded in.

The OUT animation mostly just reverses the frames and transforms:

@keyframes sideTwistBack {
  100% {
    transform: perspective(800px) translate3d(50%, 0px, -300px) rotateX(0deg) rotateY(-30deg) rotateZ(-50deg);
    opacity: 0.4;
  }
  60% {
    transform: perspective(800px) translate3d(30%, 0px, 30px) rotateX(-40deg) rotateY(-10deg) rotateZ(10deg);
    opacity: 0.8;
  }
  40% {
    transform: perspective(800px) translate3d(20%, 0px, 0px) rotateX(-50deg) rotateY(0deg) rotateZ(0deg);
    transform-origin: 50% 0;
    opacity: 0.8;
  }
  0% {
    transform-style:  preserve-3d;
    transform: perspective(800px) translate3d(0,0,0) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
    transform-origin: 0 100%;
    opacity: 1;
  }
}

Again our animation has defined 4 KeyFrames:

  • We start with no fade, translation, or rotation.
  • At 40% we have animated to an opacity of 0.8, 20% to the right and rotated -50 degrees on the X-axis. The transform-origin is now at the center top.
  • At 60% we have animated to an opacity of 0.8, 30% to the right, 30px away from us, rotated -40 degrees on the X-axis, -10 degrees on the Y-axis and 10 degrees on the Z-axis.
  • Finally we end up with an opacity of 0.4, 50% to the right, 300px away from us, rotated –30 degrees on the Y-axis and –50 degrees on the Z-Axis.

The reverse animations change the in and out directions for back button operations:

@keyframes sideTwistReverse {
  0% {
    transform-style:  preserve-3d;
    transform: perspective(800px) translate3d(50%, 0px, -300px) rotateX(0deg) rotateY(-30deg) rotateZ(50deg);
    transform-origin: 0 100%;
    opacity: 0.4;
  }
  40% {
    transform: perspective(800px) translate3d(30%, 0px, 30px) rotateX(-40deg) rotateY(-10deg) rotateZ(-10deg);
    opacity: 0.7;
  }
  60% {
    transform: perspective(800px) translate3d(20%, 0px, 0px) rotateX(-50deg) rotateY(0deg) rotateZ(0deg);
    transform-origin: 50% 0;
    opacity: 0.8;
  }
  100% {
    transform: perspective(800px) translate3d(0,0,0) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
    opacity: 1;
  }
}
@keyframes sideTwistBackReverse {
  100% {
    transform: perspective(800px) translate3d(-50%, 0px, -300px) rotateX(0deg) rotateY(30deg) rotateZ(50deg);
    opacity: 0.4;
  }
  60% {
    transform: perspective(800px) translate3d(-30%, 0px, 30px) rotateX(40deg) rotateY(10deg) rotateZ(-10deg);
    opacity: 0.8;
  }
  40% {
    transform: perspective(800px) translate3d(-20%, 0px, 0px) rotateX(50deg) rotateY(0deg) rotateZ(0deg);
    transform-origin: 50% 0;
    opacity: 0.8;
  }
  0% {
    transform-style:  preserve-3d;
    transform: perspective(800px) translate3d(0,0,0) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
    transform-origin: 0 100%;
    opacity: 1;
  }
}

Finally to use our animations, we create a class called sideTwistTrans and assign the in, out, reverse in, and reverse out animations:

.sideTwistTrans.in {
    -webkit-animation-name:            sideTwist;
    -moz-animation-name:               sideTwist;
    animation-name:                    sideTwist;
    -webkit-animation-timing-function: ease-out;
    -moz-animation-timing-function:    ease-out;
    animation-timing-function:         ease-out;
    -webkit-animation-duration:        900ms;
    -moz-animation-duration:           900ms;
    animation-duration:                900ms;
}
.sideTwistTrans.out {
    -webkit-animation-name:            sideTwistBack;
    -moz-animation-name:               sideTwistBack;
    animation-name:                    sideTwistBack;
    -webkit-animation-timing-function: ease-in;
    -moz-animation-timing-function:    ease-in;
    animation-timing-function:         ease-in;
    -webkit-animation-duration:        800ms;
    -moz-animation-duration:           800ms;
    animation-duration:                800ms;
}
.sideTwistTrans.in.reverse {
  -webkit-animation-name:              sideTwistReverse;
  -moz-animation-name:                 sideTwistReverse;
    animation-name:                    sideTwistReverse;
}
.sideTwistTrans.out.reverse {
  -webkit-animation-name:              sideTwistBackReverse;
  -moz-animation-name:                 sideTwistBackReverse;
    animation-name:                    sideTwistBackReverse;
}

Here is a Demo of the full complex 3d transition.

Although this particular animation may be a little much for most web apps, I wanted to show what can be done with CSS transitions, and to inspire you to create your own unique transitions. If you do, please feel free to share them in the comments for this post.

For further inspiration, have a look at Nifty Modal Window Effects.

Buy Me A Coffee :) @ ko-fi.com

Advertisements

2 thoughts on “Custom Page Transitions (Part 2)

Drop me a line or two ;)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s