CSS Transition Tips

css-transition-tips

CSS Transition Intro

 

The transition property is a shorthand property used to represent up to four transition-related longhand properties.

[css]
.example {
transition: [transition-property] [transition-duration] [transition-timing-function] [transition-delay];
}
[/css]

These transition properties make it possible to change element values over a specified duration, animating the property changes, rather than having them occur instantly. Here is a simple example on an animation on hover.

[css]
div {
transition: background-color 0.5s ease;
background-color: red;
}
div:hover {
background-color: green;
}
[/css]

That element in this instance a div takes half a second when moused over to turn from red to green. Here is the transition, hover over it.

See the Pen zqpEg by Louis Lazaris (@impressivewebs) on CodePen.

You can specify a particular property as above, or use “all” to refer to the transition properties entirely. div { transition: all 0.5s ease; background: red; padding: 10px; } div:hover { background: green; padding: 20px; } In this example, the background and padding will change, because of the “all” for the transition-property portion of the shorthand. You can comma separate value sets to do different transitions on different properties. div { transition: background 0.2s ease, padding 0.8s linear; }

State Jumping, Hardware Acceleration, Animating Origin, and More

 

Jump to another state mid-animation

CSS animation allow you to transition properties to a new value over a specific time. You also have the option to jump properties to a new value instantly. The key is to use two keyframes with a very tiny change, around .001% will work well.
[css] @keyframes toggleOpacity { 50% { opacity: 1; } /* Turn off */ 50.001% { opacity: 0.4; } /* Keep off state for a short period */ 52.999% { opacity: 0.4; } /* Turn back on */ 53% { opacity: 1; } }[/css]
 Here we are toggling opacity and a text-shadow to look like a flickering billboard. See the Pen No Vacancy 404 CSS Only by Zach Saucier (@Zeaklous) on CodePen.

Hardware Acceleration

Transitioning some properties, such as left and margin mean the browser is recalculating styles every frame. This is very heavy, and can lead to unnecessary re-paints. This is especially noticeable in less powerful devices, such as phones.

This best work around is to offload the rendering to the GPU using CSS transformations. This turns the element into an image during the transition, stopping any style recalculations which increases performance. A simple way of forcing the browser to hardware render an element is to set the transformation’s z axis, which you can do with translate3d:

[css]
transform: translate3d(0,0,0);
[/css]

This isn’t a complete fix and has some issues too. Don’t use this for every element and only use it when you really need to.

Hardware acceleration can cause subtle font issues, such as a font looking like a different weight. This is due to a bug where subpixel anti-aliasing isn’t supported when an element is being hardware accelerated.

One fix is to disable subpixel anti-aliasing. This is how.

[css]
font-smoothing: antialiased;
[/css]

However different browsers use different hardware acceleration, this can cause cross-browser issues. For example, whilst Chrome and Safari are both built on WebKit, Chrome uses Skia for graphics rendering while Safari uses CoreGraphics.

You can use Chrome’s Inspector to Profile the page, showing all the repaints. Additionally you can show paint triangles in the Inspector’s options, and even turn on Composited Render Layer Borders in about:flags to see which layers are operating on the GPU. The key is to reduce paints by batch updating the DOM, and move as much as possible to the GPU.

Changing transform-origin mid-animation

You can change the transform-origin and even animate it with css3! In the example below, we create one animation using rotations on different axes instead of using four separate animations.

See the Pen Change transformation-origin mid animation by Zach Saucier (@Zeaklous) on CodePen.

The bad side of this hack is that you can not use animation-mode: forwards; for only a part of an animation. Meaning that we need to re-position the element to an equivalent of its state before applying the change in transformation-origin. In the above example, this is done by using translates to mimic the rotation’s effects.

Using pseudo-elements

Pseudo elements can be made to add more content to the appearance of a single element. They can have different animations from their parent, their own box-shadows, and are very much the same to being child elements of without the HTML markup. This let’s us create amazing single element creations like the one below. See the Pen Single Element gif Recreation by Zach Saucier (@Zeaklous) on CodePen.

In the example, all of the large circles around the middle flashing circle, as well as two of the smaller circles on the rim (opposite from each other) are box-shadows on the main element. The other two small circles are part of a pseudo-element’s box-shadow and the ring made of dashes is an SVG applied as a background on the other pseudo element.

Redrawing

When transitioning, you may have two sets of CSS properties. The first set of properties that the animation starts at, and the final set of properties the transition ends on.

[css]
$(.element).css({left: 10px})
.transition({left: 20px});
[/css]

However, you’ll find that if you apply both sets of properties, one immediately after the other, then the browser tries to optimize the property changes, ignoring your initial properties and preventing a transition. Behind the scenes, browsers batch up property changes before painting which, while usually speeding up rendering, can sometimes have adverse affects.

The solution is to force a redraw between applying the two sets of properties. A simple method of doing this is just by accessing a DOM element’s offsetHeight property, like so [demo]:

[javascript]
$.fn.redraw = function(){
$(this).each(function(){
var redraw = this.offsetHeight;
});
};
[/javascript]

This will work in most browsers, but I’ve had occasions in Android where this hasn’t been enough. The alternative is to either use timeouts, or by toggling a class name.

[javascript]
$(.element).css({left: 10px})
.redraw()
.transition({left: 20px});
[/javascript]

I hope you enjoyed this deeper look into css transitions. If you know someone learning front end development, do them a favour, share it with them and help them level up too.