css_animation 0.1.8


Provides a simple wrapper around the CSS3 animation functionalities.


At the time of writing there did not appear to be a simple way to dynamically generate the CSS3 keyframes necessary for animation within dart. Therefore the appropriate rules must be built manually and injected into a stylesheet.

CssAnimation provides a simple interface with varying degrees of control that can dynamically build animation rules and apply them to elements.

Once a rule has been built it can be applied to any number of elements using the same instance of CssAnimation since it is simply using the name of that rule.

A CssAnimation instance can now be modified, but if new instances are being created continuously then call destroy() once an instance has been used to ensure that the rule is removed from the stylesheets.

Please note that it does not attempt to fallback to javascript/dart driven animations if the CSS3 capabilities are not there, it simply won't work in older browsers.


Single property

The simplest constructor for CssAnimation allows the keyframing of a single property.

import 'dart:html';
import 'package:css_animation/css_animation.dart';

  var element   = query('#element-of-interest');
  var animation = new CssAnimation('opacity', 0, 1);

  animation.apply(element, duration: 500);

The apply() function has a variety of optional named parameters which provide convenient access to the corresponding animation styles.

Multiple properties

The starting and ending state of multiple properties can be declared using Map<String, Object> where the key is the CSS property name and the object is the property value. The value must convert to a valid form via toString().

import 'dart:html';
import 'package:css_animation/css_animation.dart';

  var element   = query('#element-of-interest');
  var animation = new CssAnimation.properties(
    { 'opacity': 0, 'top': '0px' }
    { 'opacity': 1, 'top': '8px' }

  animation.apply(element, iterations: 2, alternate: true);

The example above will fade the element in at the same time as moving it down a bit, then it will do the reverse (because alternate = true) before stopping (because iterations = 2).


An animation in CSS3 is defined as a set of keyframes (between 0% and 100%) with a specific property state at each point. The most flexible constructor allows any number of keyframes to be specified (within reason).

import 'dart:html';
import 'package:css_animation/css_animation.dart';

  var keyframes   = new Map<int, Map<String, Object>>();
  keyframes[0]    = { 'opacity': 0 };
  keyframes[50]   = { 'opacity': 1, 'background-color': '#fff' };
  keyframes[100]  = { 'opacity': 1, 'background-color': '#000' };

  var element   = query('#element-of-interest');
  var animation = new CssAnimation.keyframes(keyframes);

  animation.apply(element, onComplete: () => element.appendHtml('finished'));

This time the example provided a callback function which is invoked when the animation has completed.


CssAnimation supports rule modification. A property for a specific keyframe can be changed.

animation.modify(100, 'top', '16px');

The modification will take effect next time the animation is applied to an element. If a constructor was used that only specified "from" and "to" then there will be keyframes at 0 and 100 respectively.

Alternatively, the CSS property map for a specific keyframe can be entirely replaced.

animation.replace(50, { 'opacity': 0.25, 'background-color': '#888' });

Please be aware that each modification results in a rebuild of the underlying rule, therefore excessive use may affect the performance of your application.

Shadow root

If using CssAnimation from a component with a shadow root (such as a polymer element) then the animation styles must be placed in that root instead of the document head. Simple pass the "shadowRoot" to the argument named


import 'dart:html';
import 'package:css_animation/css_animation.dart';

void main()
  // Create keyframes at 25% intervals
  var keyframes   = new Map<int, Map<String, Object>>();
  keyframes[0]    = { 'opacity': 0 };
  keyframes[25]   = { 'opacity': 1, 'left': '256px', 'background-color': '#aaf' };
  keyframes[50]   = { 'opacity': 1, 'left': '384px', 'background-color': '#aca' };
  keyframes[75]   = { 'opacity': 1, 'left': '512px', 'top': '196px', 'width': '128px', 'height': '128px' };
  keyframes[100]  = { 'opacity': 1, 'left': '630px', 'top': '256px', 'width': '256px', 'height': '256px' };

  var count = 0;
  var boxA  = querySelector('#a');
  var boxB  = querySelector('#b');
  var boxC	= querySelector('#c');
  var line  = querySelector('#line');
  var animA = new CssAnimation('top', '196px', '256px');  // Simple animation of a single property
  var animB = new CssAnimation.keyframes(keyframes);      // Fully keyframed animation
  var animC = new CssAnimation('opacity','0.5', '1.0');

  // Animation for boxB will run indefinitely
      iterations: 0,
      alternate: true,
      duration: 2000,
      timing: CssAnimation.LINEAR

  // You can pause or resume the animation by adjusting the play state:
  boxB.onClick.listen((e) =>
      boxB.style.animationPlayState = boxB.style.animationPlayState == 'paused' ? 'running' : 'paused'

  // Animation for boxA is triggered by a click and on completion
  // will append a count value inside the box.
  boxA.onClick.listen((e) {
          iterations: 2,
          alternate: true,
          duration: 500,
          onComplete: () => boxA.appendHtml(' ${count++}')

			iterations: 1,
			duration: 200,
			onComplete: () => boxC.appendHtml(' ${count}')

  // Individual properties at specific keyframes can be modified.
  // Will take effect next time the animation is applied to an element.
  int top = 320;
	querySelector('#buttonA').onClick.listen((e) {
    animA.modify(100, 'top', '${top}px');
    line.style.top = '${top + 138}px';
    top += 64;

  // Entire property maps at specific keyframes can be replaced.
	querySelector('#buttonB').onClick.listen((e) {
    boxB.style.animation = 'none';
    animB.replace(50, { 'opacity': 0.25, 'background-color': '#fff', 'font-size': '48px' });
    animB.apply(boxB, iterations: 0, alternate: true, duration: 2000, timing: CssAnimation.LINEAR);

1. Depend on it

Add this to your package's pubspec.yaml file:

  css_animation: "^0.1.8"

2. Install it

You can install packages from the command line:

$ pub get

Alternatively, your editor might support 'pub get'. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:css_animation/css_animation.dart';


Simplified access to the CSS3 animation features


Email dan@teadriven.me.uk Dan Parnham





Source code (hyperlinked)