`:
```html
```
The `#digit` div has a fixed width and a border, so it looks like a red window.
We'll make a timer: the digits will appear one by one, in a discrete way.
To achieve that, we'll hide the `#stripe` outside of `#digit` using `overflow: hidden`, and then shift the `#stripe` to the left step-by-step.
There will be 9 steps, a step-move for each digit:
```css
#stripe.animate {
transform: translate(-90%);
transition: transform 9s *!*steps(9, start)*/!*;
}
```
The first argument of `steps(9, start)` is the number of steps. The transform will be split into 9 parts (10% each). The time interval is automatically divided into 9 parts as well, so `transition: 9s` gives us 9 seconds for the whole animation – 1 second per digit.
The second argument is one of two words: `start` or `end`.
The `start` means that in the beginning of animation we need to make the first step immediately.
In action:
[codetabs src="step"]
A click on the digit changes it to `1` (the first step) immediately, and then changes in the beginning of the next second.
The process is progressing like this:
- `0s` -- `-10%` (first change in the beginning of the 1st second, immediately)
- `1s` -- `-20%`
- ...
- `8s` -- `-90%`
- (the last second shows the final value).
Here, the first change was immediate because of `start` in the `steps`.
The alternative value `end` would mean that the change should be applied not in the beginning, but at the end of each second.
So the process for `steps(9, end)` would go like this:
- `0s` -- `0` (during the first second nothing changes)
- `1s` -- `-10%` (first change at the end of the 1st second)
- `2s` -- `-20%`
- ...
- `9s` -- `-90%`
Here's `steps(9, end)` in action (note the pause before the first digit change):
[codetabs src="step-end"]
There are also some pre-defined shorthands for `steps(...)`:
- `step-start` -- is the same as `steps(1, start)`. That is, the animation starts immediately and takes 1 step. So it starts and finishes immediately, as if there were no animation.
- `step-end` -- the same as `steps(1, end)`: make the animation in a single step at the end of `transition-duration`.
These values are rarely used, as they represent not a real animation, but rather a single-step change. We mention them here for completeness.
## Event: "transitionend"
When the CSS animation finishes, the `transitionend` event triggers.
It is widely used to do an action after the animation is done. Also we can join animations.
For instance, the ship in the example below starts to sail there and back when clicked, each time farther and farther to the right:
[iframe src="boat" height=300 edit link]
The animation is initiated by the function `go` that re-runs each time the transition finishes, and flips the direction:
```js
boat.onclick = function() {
//...
let times = 1;
function go() {
if (times % 2) {
// sail to the right
boat.classList.remove('back');
boat.style.marginLeft = 100 * times + 200 + 'px';
} else {
// sail to the left
boat.classList.add('back');
boat.style.marginLeft = 100 * times - 200 + 'px';
}
}
go();
boat.addEventListener('transitionend', function() {
times++;
go();
});
};
```
The event object for `transitionend` has a few specific properties:
`event.propertyName`
: The property that has finished animating. Can be good if we animate multiple properties simultaneously.
`event.elapsedTime`
: The time (in seconds) that the animation took, without `transition-delay`.
## Keyframes
We can join multiple simple animations together using the `@keyframes` CSS rule.
It specifies the "name" of the animation and rules - what, when and where to animate. Then using the `animation` property, we can attach the animation to the element and specify additional parameters for it.
Here's an example with explanations:
```html run height=60 autorun="no-epub" no-beautify
```
There are many articles about `@keyframes` and a [detailed specification](https://drafts.csswg.org/css-animations/).
You probably won't need `@keyframes` often, unless everything is in constant motion on your sites.
## Performance
Most CSS properties can be animated, because most of them are numeric values. For instance, `width`, `color`, `font-size` are all numbers. When you animate them, the browser gradually changes these numbers frame by frame, creating a smooth effect.
However, not all animations will look as smooth as you'd like, because different CSS properties cost differently to change.
In more technical details, when there's a style change, the browser goes through 3 steps to render the new look:
1. **Layout**: re-compute the geometry and position of each element, then
2. **Paint**: re-compute how everything should look like at their places, including background, colors,
3. **Composite**: render the final results into pixels on screen, apply CSS transforms if they exist.
During a CSS animation, this process repeats every frame. However, CSS properties that never affect geometry or position, such as `color`, may skip the Layout step. If a `color` changes, the browser doesn't calculate any new geometry, it goes to Paint -> Composite. And there are few properties that directly go to Composite. You can find a longer list of CSS properties and which stages they trigger at
.
The calculations may take time, especially on pages with many elements and a complex layout. And the delays are actually visible on most devices, leading to "jittery", less fluid animations.
Animations of properties that skip the Layout step are faster. It's even better if Paint is skipped too.
The `transform` property is a great choice, because:
- CSS transforms affect the target element box as a whole (rotate, flip, stretch, shift it).
- CSS transforms never affect neighbour elements.
...So browsers apply `transform` "on top" of existing Layout and Paint calculations, in the Composite stage.
In other words, the browser calculates the Layout (sizes, positions), paints it with colors, backgrounds, etc at the Paint stage, and then applies `transform` to element boxes that need it.
Changes (animations) of the `transform` property never trigger Layout and Paint steps. More than that, the browser leverages the graphics accelerator (a special chip on the CPU or graphics card) for CSS transforms, thus making them very efficient.
Luckily, the `transform` property is very powerful. By using `transform` on an element, you could rotate and flip it, stretch and shrink it, move it around, and [much more](https://developer.mozilla.org/docs/Web/CSS/transform#syntax). So instead of `left/margin-left` properties we can use `transform: translateX(…)`, use `transform: scale` for increasing element size, etc.
The `opacity` property also never triggers Layout (also skips Paint in Mozilla Gecko). We can use it for show/hide or fade-in/fade-out effects.
Paring `transform` with `opacity` can usually solve most of our needs, providing fluid, good-looking animations.
For example, here clicking on the `#boat` element adds the class with `transform: translateX(300)` and `opacity: 0`, thus making it move `300px` to the right and disappear:
```html run height=260 autorun no-beautify
```
Here's a more complex example, with `@keyframes`:
```html run height=80 autorun no-beautify
click me to start / stop
```
## Summary
CSS animations allow smoothly (or step-by-step) animated changes of one or multiple CSS properties.
They are good for most animation tasks. We're also able to use JavaScript for animations, the next chapter is devoted to that.
Limitations of CSS animations compared to JavaScript animations:
```compare plus="CSS animations" minus="JavaScript animations"
+ Simple things done simply.
+ Fast and lightweight for CPU.
- JavaScript animations are flexible. They can implement any animation logic, like an "explosion" of an element.
- Not just property changes. We can create new elements in JavaScript as part of the animation.
```
In early examples in this chapter, we animate `font-size`, `left`, `width`, `height`, etc. In real life projects, we should use `transform: scale()` and `transform: translate()` for better performance.
The majority of animations can be implemented using CSS as described in this chapter. And the `transitionend` event allows JavaScript to be run after the animation, so it integrates fine with the code.
But in the next chapter we'll do some JavaScript animations to cover more complex cases.