CSSアニメーションで簡単に数字をジャカジャカとドラムロールさせる

# はじめに
CSSアニメーションはアイデア次第で色々なことができます。
今回CSSアニメーションのみで、数字がクルクルと上昇していくような表現を実装してみましたのでご紹介します。
手動で書くと大変ですが、プリプロセッサを使うことで簡単に実現ができました。

後述する**残念ポイント**に目を瞑れば意外と実用性はあるかもしれません。
それではスタート！

※chromeで動作確認したため、サンプルコードには-webkit-プレフィックスのみが付いています。


**[動作イメージ]**
![roll.gif](https://qiita-image-store.s3.amazonaws.com/0/58436/9109aa47-3f91-099d-be63-23fc7a3123c2.gif)

> なお実際の動作は以下で確認することができます
> http://codepen.io/nekoneko-wanwan/pen/yewjPP


# サンプルコード

```index.html
<div class="numbers"></div>
```

```style.scss
.numbers {
  /* 数値の加算とは直接関係ありません */
  font-size: 50px;
  -webkit-animation: 'zoom-in-out' 0.3s ease 2s;

  /* ここから必須 */
  &::after {
    content: '0';
    -webkit-animation:'number-roll' 2s ease 0s forwards;      
  }
}

/**
 * 数字にカンマを付けて返す強引な関数
 * ※もっとスマートにしたい
 * @param  {number} $num [元の数字]
 * @return {string} [カンマ付きの数字を文字列として返す]
 */
@function commaSeparate($num) {
  $result: $num !default;
  @if $num > 1000 {
    $result: str-insert(inspect($num), ',', -4);
  }
  @if $num > 1000000 {
    $result: str-insert(inspect($num), ',', -4);
    $result: str-insert($result, ',', -8);
  }
  @if $num > 1000000000 {
    $result: str-insert(inspect($num), ',', -4);
    $result: str-insert($result, ',', -8);
    $result: str-insert($result, ',', -12);
  }
  @return $result;
}

/* 数字上昇アニメーション */
@keyframes number-roll {
  $startNum: 0; // 初期値（好きに変更可能）
  $endNum: 7777777; // 終了値（好きに変更可能）
  $val: 0 !default;

  @for $i from 0 through 100 {
    #{$i}% {
      $val: floor(($startNum +  ($endNum - $startNum) / 100 * $i));
      content: "" + commaSeparate($val) + "";
      opacity: $i / 100;  // 数値の加算とは直接関係ありません
    }
  }
}

/* 数値上昇完了後に実行する（本筋とは無関係です） */
@keyframes zoom-in-out {
  0% {
    transform: scale(0.8);
  }
  50% {
    transform: scale(1.2);
  }
  100% {
    transform: scale(1);
  }
}
```

# ポイント

- div.numbersの::after要素にcontentとしてテキストを格納します
- keyframesの`0%->100%`に合わせて、終了値に達するまで数値を加算していきます
- 数字の3桁ごとにカンマを加えたく、専用のfunctionを用意します

> 本当はsassのデフォルト機能のみで3桁区切りを実装したかったのですが、やり方が分からなく強引になってしまいました。拡張なしで上手くやる方法があればご教授ください...

やっていることは単純で、CSSにダーッと値を書いているだけです。

```コンパイルされたstyle.css
.numbers {
  font-size: 50px;
  -webkit-animation: 'zoom-in-out' 0.3s ease 2s;
}
.numbers::after {
  content: '0';
  -webkit-animation: 'number-roll' 2s ease 0s forwards;
}
@keyframes number-roll {
  0% {
    opacity: 0;
    content: "0";
  }
  1% {
    opacity: 0.01;
    content: "77,777";
  }
  2% {
    opacity: 0.02;
    content: "155,555";
  }
  /* ... 略 ... */
  100% {
    opacity: 1;
    content: "7,777,777";
  }
}
/* ... 略 ... */
```

# 残念なポイント

お待ちかねの残念なポイントです！

- CSSの肥大化
- 動的な修正ができない
- 非対応ブラウザの存在
- SEO的には良くなさそう

**CSSの肥大化**
keyframes内で1%単位ごとにプロパティを定義しているため、どうしてもコンパイル後のコード量が大きくなってしまいます。その上prefixが付いた暁には...

なお以下のようにフレームごとのパーセント上昇率を上げることで、コード量を抑えることもできます。※当然アニメーションの滑らかさは落ちますが

```パーセントの上昇率を上げる.scss
@for $i from 0 through 20 {
  #{$i * 5}% {
    $val: floor(($startNum +  ($endNum - $startNum) / 100 * $i * 5));
    opacity: $i * 5 / 100;
    content: "" + commaSeparate($val) + "";
  }
}
```
```パーセントの上昇率を上げる.css
0% {
  opacity: 0;
  content: "0";
}
5% {
  opacity: 0.05;
  content: "388,888";
}
10% {
  opacity: 0.1;
  content: "777,777";
}
/* ... 略 ... */
```

**動的な修正ができない**
CSSコンパイル時に全て計算をしているため、コンテキストに応じて値を変えるといった動作はできません。複雑なものには素直にJSを使いましょう。また数値を変更したい場合には、scssファイルの修正とコンパイルが必要なので手間です。

**非対応ブラウザの存在**
これは言わずもがなですネ（旧IEのサポートは切れましたが、念のため）。

**SEO的には良くなさそう**
after擬似要素にテキストを突っ込んでいるので、SEO的に問題が無いとはあまり思えません。もし数値自体に重要な意味がある場合は、別途要素を用意したり何とかした方が良いかもしれません。


# 終わりに

いかがでしょうか。ちょっとしたアクセントに使えるかもしれませんね！
私なら大人しくJSを使います。


> [参考までに]
> [CSSアニメーションを使いこなすために知っておきたい5つのこと](http://qiita.com/nekoneko-wanwan/items/e8114c6e34d2950a7b28)