Full-page Animations Using CSS


Internet Explorer Team Blog

Full-page Animations Using CSS

  • Comments 79

Internet Explorer 9 introduced support for CSS 2D Transforms. Internet Explorer 10 Developer Preview added support for CSS 3D Transforms and CSS Animations. By tapping the power of your GPU and running asynchronously from regular JavaScript, these IE10 features provide a more performant and flexible alternative to traditional script-based animations for Web content.

In previous blog posts, we covered CSS 3D Transforms as well as CSS Animations and Transitions. In this post, we introduce a more “unconventional” use case for these technologies by describing the concept of “full-page animations” that can be used during the navigation process to add fluidity and continuity to browsing. Our target is to achieve a seamless browsing experience in which content smoothly appears into view when the user visits a page and transitions away when he clicks on a link or performs a relevant action.

These effects can be accomplished by transforming the HTML <body> element using CSS Animations. However, this use case presents some considerations that we felt were worthy of discussion, such as the effect of layout and sizing on transforming <body>, as well as how to appropriately time page navigations so that they mesh properly with our animations.

The code samples in this post use unprefixed CSS markup as supported by IE10 Release Preview; other browsers may require vendor prefixes for the CSS Animations and CSS Transforms properties used.

Transforming a Page’s Entire Content

CSS Transforms are defined on the stylistic properties of an HTML DOM Element. For example, the markup for rotating an element 45 degrees along its Z axis would look like this:

#element {

transform: rotateZ(45deg);


Attaching a transform to the <body> element of your HTML document works exactly the same way. So performing in order to declaratively add the same effect to your document’s <body> you could do something like this:

body {

transform: rotateZ(45deg);


Let’s look at a before-and-after shot of a page when applying a transform to the body element:

Screen shot showing applying a rotateZ(45deg) transform to the body element of a document
Applying a rotateZ(45deg) transform to the body element of a document.

For three dimensional transformations, the CSS Transforms specification defines the perspective property that can be specified on the parent of the element that we transforming. When transforming the <body> element of your content, it has to be applied to the <html> element that resides above it in the DOM hierarchy. Doing so is straightforward:

html {

perspective: 500px;


Combining this with a rotateY(45deg) transform on the <body> element yields the following result:

Screen shot showing applying a rotateY(45deg) transform to <body> with perspective: 500px set on <html>
Applying a rotate(45deg) transform to <body> with perspective: 500px set on <html>.

We can manipulate the transform-origin property on the body element for interesting results. Let’s look at a couple of examples:

body {

transform-origin: 50% 100%;

transform: rotateX(45deg);


The above markup sets a rotation along X for the body element while shifting the origin of rotations to the bottom of the element using transform-origin. Effectively this rotates the document’s contents “into” the screen like this:

Screen shot showing applying transform: rotateX(45deg) and transform-origin:  50% 100% to <body>

We can also manipulate the perspective-origin property on the root element of our document to achieve an off-axis projection effect. Changing the style for <html> to:

html {

perspective: 500px;

perspective-origin: 90% 50%;


Our page now looks like this:

Screen shot showing applying perspective: 500px and perspective-origin: 90% 50% to the <html> element

By using CSS Transforms, we can easily manipulate the visual appearance of the entirety of our page’s content. Since the usual layout and sizing rules still apply, some transforms on the body element (particularly ones that use percentage values or rely on the transform-origin property) can result in different visual effects depending on the content of our page. Recall our previous rotateX(45deg) example with transform-origin set to 50% 100%.

Below you can see the results before and after the transform is applied.

Screen shot highlighting the difference in scroll bars before and after the application of a transform under perspective projection

Notice how the content does not actually pivot on the bottom of the window but rather at some point outside of the viewport. This is expected behavior for CSS Transforms: the <body> is laid out normally, then it is rotated along its bottom edge that is somewhere off screen. You will also notice that the actual foot print of the content has expanded (take a look at the scroll bars in the “after” picture) in order to accommodate the transformed content (the fact that we are using perspective projection makes this effect even more pronounced).

So how do we deal with arbitrarily sized content when applying transforms to our body element? Custom tailoring all content in order to ensure that the size of the body does not expand more than a certain amount may be unrealistic. Instead, we can use a simple HTML/CSS pattern that allows us to fix the size of the body element to that of the browser window and append content inside a wrapper <div>. The following markup achieves just that:

html, body {

width: 100%;

height: 100%;

min-width: 100%;

max-width: 100%;

padding: 0;

margin: 0;

overflow: hidden;



#Wrapper {

position: absolute;

width: 100%;

height: 100%;

overflow: scroll;


The illustration below shows what happens when a page is scrolled vertically and we apply a rotateY(45deg) transform to the <body> element of our document directly (left) and using the wrapper pattern (right):

Screen shot showing what happens when a page is scrolled vertically and a rotateY(45deg) transform is applied to the <body> element under perspective projection, with and without a wrapper CSS/HTML pattern

The direct application of the transform results in a skewed visual result due to the off-axis projection (since we are no longer looking at the “center” of the body element). Using the wrapper pattern ensures that the <html> element’s perspective-origin property (50% 50% by default) will always be correctly centered with relation to the <body> element, giving us a pleasant visual effect.

By utilizing the above pattern and setting up CSS Transforms with percentage values whenever possible, we can affect our <body> element in consistent ways, regardless of the size of its contents.

From Transforms to Animations

Having sorted out the intricacies of applying CSS Transforms to the <body> element, CSS Animations are the next step. By following the principles described above, we can create animations that bring our Web content into view (or remove it from view) in interesting ways.

Consider this basic @keyframes rule:

@keyframes rotateInLeft {

from {

transform-origin: 0% 0%;

transform: rotateY(180deg);


to {

transform-origin: 0% 0%;

transform: rotateY(0deg);



When applied to an element, this animation will cause it to rotate on its left side. When applied to a <body> element that uses our wrapper pattern the visual result is more interesting. The document will actually rotate from outside of the visible area of the browser window and into full view:

Three screen shots in sequence showing the affect of applying the "rotateInLeft" animation

Similarly, we can compose animations that fluidly remove our Web content from view. For example, if we wanted our page to disappear into the distance while rotating, we could use something like this:

@keyframes whirlOut {

to {

transform: scale(0) rotateZ(1260deg);



With the visual result being:

Three screen shots in sequence showing the affect of applying the "whirlOut" animation

Since we can use the full power of CSS Animations to affect the entirety of our Web content, we have a lot of flexibility in terms of generating these page effects (and we are certainly not limited to just using CSS Transforms). But once we have composed the effects that we want to apply to our content, how do we cause them to trigger during the page navigation process?

Attaching Animations to <body>

Our goal is to use trigger animations at strategic times during the browser experience in order to give the appearance of content transitioning into view when a page loads and out of view when the user clicks on a link.

The first intuitive place to add an animation to the body element would be the onload JavaScript event. As it turns out however, adding an animation when onload fires is actually too late. This event actually triggers when the entirety of the content in our page has finished loading (including any images or other bandwidth-intensive resources). Attaching an animation to onload on a bandwidth-intensive page would result in our content displaying “normally,” followed by the animation triggering and re-bringing the content into view. Not exactly the effect that we were aiming for.

Alternatively, we could utilize the DOMContentLoaded event that triggers when the browser has finished parsing the DOM structure of our content (but potentially before resources have finished loading). The IE Test Drive DOMContentLoaded demo illustrates the difference between these two events. However, in cases of complex Web content, a modern browser may choose to perform “progressive” rendering, displaying the page before the entirety of the DOM tree has been loaded. In these situations, the visual result would be similar to the onload scenario.

The optimal place to set up an animation that transitions our page content in view is inline at the top of the <body> element. This ensures that the animation will commence right as the content is being rendered (and that the starting position of the content will be that of the from keyframe of our selected animation). A pleasant side effect of this approach is that the animation may actually mask any progressive rendering, re-layout or resource loading that can occur with complex content.

Setting up the animations that transition our content out of view is also interesting. One could assume that we could attach an onclick handler to all elements of interest in our content (for instance all <a> tags) and just set the relevant animation properties (animation-name, animation-duration, etc.) in the callback function. However, if we do not actually delay the navigation from happening, we will not see our expected fluid transition.

This is a good opportunity to utilize the animation events described in the CSS Animations specification. In particular, we can use the animationend event to detect when the animation has completed and then trigger a navigation (by setting window.location.href, for instance). Thus our onclick will trigger the “remove-from-view” animation and register a handler for animationend on <body> that will ensure that the navigation event occurs.

Live Demo Available

We’ve created a demonstration and tutorial on bringing pages alive with CSS Transforms & Animations that provide depth and examples beyond what we’ve been able to show here. The tutorial itself utilizes full page animations during page navigation that work in Internet Explorer 10 on Windows 8 as well as recent versions of Chrome and Firefox..

To simply enjoy the page-to-page animations, step through the pages of the tutorial using the “Continue to ...” links in the lower right corner of each page.

At the end of the tutorial we provide some additional guidance and sample code on how to incorporate these animations with your own Web content.


CSS Transforms and CSS Animations are two powerful feature-sets that enable richer and more immersive Web experiences. This blog post outlined the considerations of using CSS Transforms and CSS Animations to bring the entirety of your Web content to life. With a small amount of effort you can create Web pages (even static ones) that provide a fluid and almost app-like navigation experience.

—Charilaos “Harris” Papadopoulos, Program Manager Intern, Internet Explorer Graphics

  • Loading...