Independent Composition: Rendering and Compositing in Internet Explorer 10

The purpose of this topic is to educate web developers about independent composition, an architectural mechanism that improves the user experience by separating certain web platform rendering and composition from the user interface thread. This topic provides guidance for when independent composition is supported and identifies the specific scenarios that can cause content rendering to fall back to dependent composition. This content is intended for advanced web and app developers who want to improve the performance of their complex websites or apps.

The information contained in this topic applies to the following platforms:

  • Internet Explorer 10
  • Windows Store apps using JavaScript

Note  This topic applies to both Internet Explorer for the desktop and Internet Explorer in the new Windows UI.

Overview

Independent composition brings the fast and fluid Windows 8 experience to Windows Store apps using JavaScript and Windows Internet Explorer. Built directly into the Windows web platform, independent composition creates a smooth, glitch-free user experience.

To provide this enhanced experience, functionality such as animation, video, and touch-based panning are rendered and composited independently from the web platform's UI thread. Because this work has been offloaded onto a separate thread, these scenarios are no longer at risk of being blocked by UI thread operations such as JavaScript execution.

DirectComposition is a dedicated system-level bitmap compositor that runs independently of the web platform. It is used to independently compose select HTML Document Object Model (DOM) elements. Independent composition offloads composition work from the web platform and the CPU to the graphics processing unit (GPU) using the DirectComposition component.

Independent composition is supported in the following scenarios:

  • Animation: Certain animations can be computed and composed independently by the compositor itself.
  • Video playback & canvas*:* Video frames can be decoded and presented directly to the compositor without involving the UI thread.
  • Panning and zooming: A separate user-input thread can be used to manipulate a pannable or zoomable piece of web content in response to touch actions.
  • Fixed-positioned elements: Fixed-positioned elements can be composed independently to maintain correct visual drawing order of overlaying elements.

How does independent composition work?

To understand independent composition, you must first learn about the concept of layering and about explicit layers and implicit layers.

Layering

The web platform determines when and how DOM elements are presented to the screen. When web content comes into view, DOM properties are updated and the web platform initiates a layout pass. Both Windows Store apps using JavaScript and websites running in Internet Explorer 10 trigger layout when DOM property values are changed. During a layout pass, specific elements are flagged for independent composition.

Diagram of a layout pass, where certain elements are flagged for independent composition

Once a DOM element is flagged for independent composition, it is placed into its own layer. Layers created in this way are called explicit layers, and they're created in all of the four scenarios listed previously (animation, video/canvas, panning/zooming, and fixed elements). Explicit layers are passed to the system-level compositor, DirectComposition, which runs independently from the UI thread. All other DOM elements are rendered dependently (that is, by the UI thread) to a single "base" layer. It is possible to have independent and dependent content within the same window.

Diagram illustrating the independent elements and the dependent elements that can exist on a single page

Each independent layer comes with the cost of additional video memory and setup time required to offload work from the UI thread. The more layers that are created, the higher the performance cost becomes. As a result, it is important to identify the scenarios where layers are created and how long layering resources are being used (see Supported Scenarios).

Layers are destroyed when they're no longer needed, and the associated resources are released. For independent animations, this occurs when the animation completes. For independently composed elements (such as HTML video), the layer will remain until the element is no longer visible.

Note  

An element is considered to no longer be visible if either of the following is true:

  • The Cascading Style Sheets (CSS) visibility property of the element is set to "hidden"
  • The display property of the element is set to "none"
  • The element is outside the bounds of the viewport

Implicit Layers

Implicit layers are created for elements that overlap content that is explicitly targeted for independent composition (independent layers). These layers are known as implicit layers since they do not fall into the explicitly defined supported scenarios. As with explicit layers, implicit layers are composed independently from the UI thread.

Implicit layers have the same resource requirements as explicit layers, so you should avoid scenarios that could cause them to be created unnecessarily. You should avoid overlapping non-explicitly-layered elements with explicitly layered elements unless absolutely necessary. Due to the performance cost of layer creation, there is a limit of 20 implicit layers per app or browser tab.

The following example demonstrates a scenario where an implicit layer is created. Layer 1 is an explicitly layered element and Layer 2 is an element that is positioned on top of the independently composed Layer 1. We know that Layer 2 is on top because it has a higher z-index than Layer 1. Since Layer 2 overlaps the explicitly layered Layer 1, Layer 2 is placed into an implicit layer.

Diagram showing two layers: Layer 2 is smaller than Layer 1 and lies on top of it

To obtain the best performance out of independent composition, you should design your content so that the need for implicit layers is minimized. In particular, you should avoid overlapping explicitly layered elements with other content. You can do this by placing independently composed elements as high as possible in the z order via positioning. You should also avoid overlapping independent elements with other elements.

The lifetime of an implicit layer is equal to the lifetime of the explicit layer which triggered its creation.

Returning to the Layer 1 and Layer 2 example, let's assume the reason that Layer 1 is explicitly layered is because it's being animated. Once the animation completes, both Layer 1 (the explicit layer) and Layer 2 (the implicit layer) will be destroyed. This is necessary to maintain the proper z-order for both elements, because the element in the implicit layer is above an element in an explicit layer. Additionally, if an implicit layer can't be created for an element (see Unsupported Scenarios), then no layers can be created for elements positioned beneath it. This means that all elements below the top element will be dependently composed.

Supported Scenarios

This section contains several scenarios in which independent composition is supported.

Independent Animation

Independent animation is used for Cascading Style Sheets, Level 3 (CSS3) animations and transitions when applied to either the CSS transform or opacity properties. Animation of these properties results in an element being independently rendered and composed; be aware that independent composition of the element only occurs for as long as the animation is in progress. Because these animations are on a separate thread, they are no longer at risk of being blocked by UI thread operations (for instance, executing script). This results in smooth and glitch-free animations. There is no additional work or markup required for you to leverage independent animation in your content, though there are certain cases and guidelines that you should follow when creating custom animations, and they are discussed in Unsupported Scenarios.

The Windows 8 Animation Library is designed to fully employ independent animations. If you are creating custom animations, you are encouraged to take advantage of independent animations by creating your animating UI using CSS animations and transitions of the CSS transform and opacity properties only.

Supported Properties

In general, CSS3 transitions and animations of CSS transforms and opacity will be independent. CSS transforms and opacity effects are composed independently because they don't affect content layout, and layout computations are performed on the UI thread. Since animating transforms and opacity doesn't require use of the UI thread, it can be performed on a separate thread.

Each of these properties is detailed in one of the following sections:

The following CSS properties are not supported with independent composition (see the Unsupported Scenarios section for more details).

Implicit Layers and Independent Animation

Once an independent animation is applied to an element, the animation path is mapped out and all elements that intersect the animation path are placed into layers. If an intersecting element was not previously targeted for independent composition, it will be placed into an implicit layer. These layers are created when the independent animation is applied and are destroyed when the animation completes.

In the following diagram, the circle in the light blue box is targeted for independent animation and the animation path is mapped out by the orange arrow. The elements in the green boxes (that is, the triangle and star) intersect with the path of the animation and are consequently implicitly layered for the duration of the animation.

Diagram of the animation process and layering

HTML5 video tag

The HTML5 video tag is an element that is explicitly targeted for independent composition. Independently rendering and composing HTML5 video enables a fast and smooth media playback experience. Independent HTML5 video also enables unique capabilities such as stereo video support and a more secure Digital Rights Management (DRM) to the Media Platform. (You can use the MediaProtectionManager API to add DRM to HTML5 video content in Windows Store apps using JavaScript.)

For additional information, see Audio and video performance.

Scrollable Elements

You can use the CSS overflow property to specify whether content can overflow an element's content box. When "overflow: scroll" or "overflow: auto" is defined on an HTML element such as body or div and the element has enough content to overflow its box, the element becomes both scrollable and independently composed. Scrollable elements clip content to the size of the content box and scrollbars are rendered on the element so additional content can be scrolled into view. Scrollable elements are specifically targeted for independent composition.

<style>
  #scroller1 {
    width:100px;
    height:100px;
    overflow:scroll;
  }
</style>
...
<div id="scroller1">
  This div is now scrollable and is independently composed.
</div>

Zoomable Elements

Similar to elements that can be scrolled, an element can become zoomable by setting the -ms-content-zooming property to "zoom". Once this property value is declared and the element permits overflow ("overflow: auto"), the element is targeted for independent composition.

<style>
  #scroller1 {
    width:100px;
    height:100px;
    -ms-content-zooming: zoom;
    overflow: auto;
  }
</style>
...
<div id="scroller1">
  This div is now zoomable and is independently composed.
</div>

Fixed Elements

Another scenario that is targeted for independent composition is declaring a DOM element as "position: fixed".

Although fixed positioned elements are supported independently, you should avoid nesting fixed elements.

Unsupported Scenarios

This section describes scenarios that should be avoided when designing Windows Store apps using JavaScript or websites intended for Internet Explorer 10.

General

The first subsection describes some general scenarios.

Layer count and size threshold

Each layer that is created requires video memory resources. Restrictions around layer size and count are used to ensure good independent composition performance.

For each independent composition scenario there is a limit of 300 independently composed elements at any given time. Each independently animated element counts as a single independently composed element, while a scrollable element counts as three. This means that a single page can have up to 100 scrollable elements or 300 elements animating the CSS transform or opacity properties simultaneously (for more information, see Independent Animations in this section).

Along with the layer count limit, there is a cumulative layer size limit for all on-screen elements. At any given time, the combined size of all layers can't be more than 10 times the size of the viewport. For example, if a Windows Store app using JavaScript or website in Internet Explorer 10 has a viewport size of 1280×800 pixels, only ten full screen elements can be layered at once. However, a Windows Store app using JavaScript can have a total of 40 elements, each with a size of 640×400 pixels, on the screen at once. These layered elements must be on the screen and can overlap with each other.

These count and size limits are enforced to prevent extreme scenarios from impacting system performance. You should be aware of these limits and design your content to be well below these thresholds whenever possible.

Implicit Layer Limit

As mentioned earlier, there is a maximum limit of 20 implicit layers that can be allocated at any given time. If more than 20 implicit layers are required to independently compose an element, the element will fall back to dependent composition. For example, if an element which is explicitly targeted for independent composition has over 20 overlapping elements that aren't explicitly targeted for independent composition, both the element and the overlapping elements will be composed dependently.

Since implicit layers are most commonly created because of the use of absolute and relative positioning, we recommend the following:

  • Avoid extensive use of positioning to achieve what can be done through nesting and more advanced layout constructs such as grid and multicolumn layouts
  • If you can't avoid positioning, try to limit the number of elements that use positioning, and specifically avoid extensive overlapping of elements

CSS Outline on scrollable elements

If a CSS outline is applied to a video or canvas element or an element that is scrollable, the element will be composed dependently. Child elements targeted for independent composition will still be composed independently.

<style>
  div {
    overflow: scroll;
    outline-color: red;
    outline-style: solid;
  }
</style>

To work around this behavior, try creating a dummy parent HTML element that has the CSS outline. However, this workaround will only work if the color of the outline is anything other than "invert".

Outline-color set to "invert"

When the CSS outline property is defined, the initial value for outline-color is set to "invert". Setting outline-color to "invert" ensures that the focus border is visible, regardless of background color.

Setting the outline-color property to a valid value other than "invert" will not cause an independent animation to fall back to the dependent case. However, if "outline-color:invert" is set on an element that is targeted for independent animation, the animation, children, and ancestors will all be animated dependently.

<style>
  div {
    outline-color: invert;
    outline-style: solid;
  }
</style>

The only way to work around this behavior is to use a real color value instead of "invert".

Inline Containers

In CSS, you can specify "display: inline" on HTML elements. Any element that has had its display property explicitly set to "inline" or has a default display value of "inline" (such as the span element) will not be independently animated.

If an element that has been targeted for independent composition is overlapped by an inline element, it will not be independently composed. This is because all elements in the path of an independent animation must be layered, even before intersection with the animating element occurs. Inline elements cannot be placed into an implicit layer, which means that any animation that intersects with an inline element will be dependent.

Negative Z-index

Web developers commonly use the CSS z-index property to specify the stacking order of HTML elements. This property allows you to place elements in front of or behind other elements, and accepts both positive and negative numbers. Given two elements, the element with the larger stacking order is always drawn in front of the element with the lower stacking order. You should avoid negative z-index values because they can result in elements overlapping that cannot be layered.

Fixed Background

Fixed background is supported independently only when applied to either the body or html elements.

If an element (other than html or body) or its descendants has either the background or background-attachment CSS properties set to "fixed", as shown in the following code example, the element will not be independently composed.

<style>
  div {
    background-image: url(“test.png”);
    background-attachment: fixed;
  }
</style>

Windowless ActiveX controls

Windowless (that is, Windows Graphics Device Interface (GDI)-based) Microsoft ActiveX controls are controls that can make use of their container's window, rather than creating a new window of their own. These controls are not supported in Windows Store apps using JavaScript. In Internet Explorer for the desktop, windowless ActiveX controls are supported, but they can't be independently composed.

Binary Painters (DirectDraw-based only)

Third party Microsoft DirectDraw-based binary painters (such as custom invert, shadows, waves, and so on) are not supported independently. Binary painters are used by web developers to specify custom rendering behaviors such as a blur for a window. These behaviors are not supported by the independent composition engine and require work to be done on the UI thread. Similar to the windowless ActiveX scenario, these controls are not composed independently.

Visibility set to hidden

The visibility CSS property is used by developers to specify whether an element is visible on the screen. If an element is not visible on the screen, there is no reason to use resources to place it and its content into a layer.

You should be aware of where and when visibility is set to hidden. If it is set on an element or its ancestor, the element will not be independently composed. The visibility property is useful when trying to hide elements on the screen while maintaining an element's location in layout.

If visibility is used to hide an element before animating, the animation values must be set after the element's visibility property has been set to "visible". If the animation values are defined while the element's visibility property is set to "hidden", the animation will be dependent.

Opacity Zero

As with "visibility: hidden", if an element or its ancestor has the CSS opacity property set to "0", the element is not visible on the screen and a layer isn't created.

If opacity is set to "0" on an element that is targeted for independent animation, the element will be independently animated once it is visible on the screen. It is also possible to independently animate to or from an opacity of "0".

Setting "opacity: 0" on an ancestor element can impact the independent composition of all its child elements. For example, an animation will be dependent if the independently animating element has an ancestor with "opacity: 0" set before the start of the animation. Even if the ancestor's opacity becomes greater than 0 during the duration of the animation, the animation will not be independent.

You should be aware of this restriction when you are independently animating infinite-duration animations. Because of this scenario, an infinite animation must be canceled and then re-applied to achieve independent composition.

Independent Animations

Certain restrictions apply when using independent composition. The following sections discuss some unsupported independent animation scenarios. In other words, even if an element is using the correct CSS3 animation or transition of the CSS transform or opacity properties, it will not independently animate if any of the following conditions also apply to the same element.

These conditions may be true for other elements on the page (those not being independently animated) and will not affect the independently animating element. These conditions apply on a per-element basis.

Independent animation count and size threshold

Due to the performance cost of independent composition that was described earlier in this topic, scenarios are limited to no more than 400 independent property animations or 300 independently animating elements at any given time. Each independent property animation counts as one independent animation. For instance, if a single CSS animation contains both transform and opacity properties, this counts as two independent property animations for one independently animating element.

This means a scenario can have a transform and opacity animation on a maximum of 200 elements (which equals 400 independent property animations) or a maximum of 300 elements with a single property animation of either transform or opacity (300 independently animating elements).

In addition, the size of an independently animating element is limited to 8,000 pixels. If an element's height or width is greater than the 8,000-pixel size limit, it will not animate independently, but will instead animate dependently on the UI thread.

If any of these limits are exceeded, the scenario will not be composed independently and will be executed on the UI thread.

Relative unit resolution base changes

If an independent animation is animating to a relative unit value (other than pixels) and the base unit of the animating property changes during the duration of the animation, the animation will fall back to dependent composition. By changing the base unit value, the relative unit values that are being independently animated must be recalculated, and this work is done on the UI thread.

This restriction impacts animating and transitioning transform values while dynamically changing the base unit of the animating value.

In the example below, the base unit of the translateX (width) transform function is changed 1 second into the animation called move. Once the change of the base unit is detected, the animation becomes dependently composed.

<style>
  #box {
    animation: move 5s;
    width: 100px; 
  }
  @keyframe move {
    from {transform: translateX(10px); }
    to {transform: translateX(200%); }
}
</style>
<script>
  function changeWidth() {
    var elem = document.getElementById('box');
    elem.style.width = '200px';
  }
</script>
<html>
  <body onload="setTimeout('changeWidth()',1000)">
    <div id="box"></div>
  </body>
</html>

Toggling visibility while an element animates

If an animating element's visibility property is set to "hidden" and then back to "visible" during the course of the animation, it will no longer be independently animated unless the animation is reapplied. You should set the visibility of all animating elements to "visible" before applying an animation.

If an element undergoing an infinite animation ("animation-iteration-count: infinite") is hidden and made visible again via the visibility property, it will never be independent unless the animation is canceled and reapplied. Instead of using visibility for this infinite animation scenario, you should use "display:none" and "display:block" to hide and reveal the UI element.

Note  Declaring "display: none" will cancel a running animation or transition.

Switching from play-state:paused to play-state:running

As with toggling the CSS visibility property, if animation-play-state goes from "paused" to "running", the running animation will not be independent. This is because "animation-play-state:paused" is not targeted for independent composition. Once this value is declared, the element will not be independently composed until the animation is removed and re-applied.

Animating or transitioning transform-origin

Independent animation does not support the transform-origin property; this property animates dependently on the UI thread. If an element is targeted for independent animation and has an animation or transition of transform-origin, the transform animation or transition of the element will be dependent. If there is an independent animation of transforms and opacity, the opacity animation will be independent while the transform animation will be dependent.

Following is a code example that illustrates this scenario:

<style>
  div { animation: move 5s, origin 5s; }

  @keyframes move {
    from { transform: rotate(0deg; }
    to { transform: rotate(180deg);}
  }

  @keyframes origin {
    from { transform-origin: 10px; }
    to { transform-origin: 100px; }
  }
</style>