CSSの@keyframesを使ってサンバを踊る顔文字を作った

# 前置き
皆さま、まだまだ夏ですね。誰が何を言おうとまだ夏。
過ぎ去る夏にイヤダ、ヤメテ、イカナイデと駄々をこねております。悲しいですね。
そんな秋まっしぐらの今日この頃、いかがお過ごしでしょうか。初投稿です。

私、この４月から社会人１年目をやっておりまして、７月まで研修を受けていました。
本日は研修期間中に作ったしょーもない成果物について、紹介させていただきます。
同期内から割と好評を頂いておりまして、当時は幾分気持ちよくさせていただきました。
今回はせっかくなので、そのしょーもないものを紹介するしょーもない記事を書くことにしました。

# 本編
なぜ私がこのような物を作ったのか、突如インスピレーションしたのかもしれないし、
５月中旬の時の、私の精神状態がおかしかったのかもしれない。
ただ、同期の中では、想定外の事実に直面した時に思わず声をあげてしまうような人間がいたことや、
デバッグで頭がおかしくなってしまった時に、サンバを踊る文化があったことだけは事実である。

前置きは置いといて、本成果物はGitHub Pagesで公開している。
https://yuichisemura.github.io/sambadejaneiro/

codepen を貼るが横幅が足りずにずれるので、一応↑をみていってほしい。
<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="js,result" data-user="yuichisemura" data-slug-hash="pozaEXJ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="pozaEXJ">
  <span>See the Pen <a href="https://codepen.io/yuichisemura/pen/pozaEXJ/">
  pozaEXJ</a> by Yuichi Semura (<a href="https://codepen.io/yuichisemura">@yuichisemura</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

本記事では、その中からCSSを中心に紹介したいと思う。
当人、ほぼ無知の状態からスタートしている。勉強の備忘録と捉えてほしい。
成果物を見てわかる通り、たいした記事ではない。

# 何これ
「２１人（＋１人）の顔文字が、Ctrl＋Enterを押すことで、
sambaモードとsnakeモードを行ったり来たりするページ」だ。
snakeモードでは皆隠れている。マウスをホバーされると姿を表す。
sambaモードでは皆楽しそうに、『samba de janeiro』を踊る。

当時は同じ部屋に21人の同期が居て、日々サンバを踊って研修をしていた。
その光景を再現し、社内のポータルサイトに公開した。

# JavaScript (samba.js)
「jsで書いた？」とよく聞かれたが、ほぼ書いていない。
とは言っても書いたものは書いたのだが、本ページにおけるJavaScriptの役割は、
キーボードのイベントをトリガーにモードの切り替えを行ったのみで、肝心の動きはCSSで設定している。
実を言うと作り始めた頃は、これほどまでCSSがanimationに対応しているとは知らなかった。

というわけで、ただただ Ctrl＋Enter が押されたら start() か stop() が呼ばれ、
ページの要素の class が付け替えられて、 CSS が反応しているだけである。

```js
window.addEventListener("keydown", handleKeydown);
window.addEventListener("keyup", handleKeyup);
var sambaNow = false;
var enterFlg = false;
var ctrFlg = false;
function handleKeydown(event){
    if(event.key === 'Enter'){
        enterFlg = true;
    }else if(event.key === 'Control'){
        ctrFlg = true;
    }
    if(!enterFlg || !ctrFlg) return;
    if(sambaNow){
        stop();
    }else{
        start();
    }
    sambaNow = !sambaNow;
}

function handleKeyup(event){
    if(event.key === 'Enter'){
        enterFlg = false;
    }else if(event.key === 'Control'){
        ctrFlg = false;
    }
}
// start() stop() は省略
```

# HTML(index.html)とCSS(samba.css)
HTML はだいたいこんな感じである。

```html
<body>
<div id="all1" class="all">
<div id="Row1" class="yurezu">
<p class="left">＼</p><p class="face">(^p^)</p><p class="right">／</p>
<p class="left">＼</p><p class="face">(^u^)</p><p class="right">／</p>
<p class="left">＼</p><p class="face">(^s^)</p><p class="right">／</p>
<p class="left">＼</p><p class="face">(^h^)</p><p class="right">／</p>
<p class="left">＼</p><p class="face">(^c^)</p><p class="right">／</p>
<p class="left">＼</p><p class="face">(^t^)</p><p class="right">／</p>
<p class="left">＼</p><p class="face">(^r^)</p><p class="right">／</p>
<p class="left">＼</p><p class="face">(^l^)</p><p class="right">／</p></div>
<div id="Row2" class="yurezu"><!-- 略 --></div>
<div id="Row3" class="yurezu"><!-- 略 --></div>
</div>
<br>
<div id="haka" class="bokete"><!-- 墓 --></div>
</body>
```

構成を図解したものがこんな感じである。
<img width="800" alt="プレゼンテーション1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387790/15acae78-2463-82e2-61b5-e3c746019a2a.png">
全体は大きく３段の div 要素に分かれている。idは Row1、Row2、Row3 とつけている。
Row1とRow3は中央→左→中央→右→中央...と繰り返す。
Row2は中央→右→中央→左→中央...と繰り返す。
このようにすることで、全体が列を形成して動いているように見えている。

次に顔文字の詳細であるが、信号機みたいな色分けで表している部分である。
p要素のleft、face、rightで構成されている。

## 左手中心の生活
まず顔文字の説明をする。

顔文字はleft、face、rightに分かれていて、それぞれ違う動きを持たせている。

左手は中央→上→中央→下→中央...を繰り返す。
顔はただただ少しだけ揺れるのを繰り返す。
右手は中央→下→中央→上→中央...を繰り返す。

実装例として、左手のCSSを以下に示す。
（本当は右手なんだけどこっちからは左に見えるのでそういうことだ。）

```css
.left { 
    display: inline-block;
    margin-top: 3px;
    height: 10px;
}
.hurueruLeft {
    animation: huruLeft infinite;
    animation-duration: 902ms;
}
@keyframes huruLeft {
    0% {transform: translateY(0px)}
    25% {transform: translateY(-10px)}
    50% {transform: translateY(0px)}
    75% {transform: translateY(5px)}
    100% {transform: translateY(0)}
}
```
**.left**は配置系設定を持ち、**.hurueruLeft**はアニメーションの設定を持っている。
モード切り替えによって、**.left**を持つ要素に**.hurueruLeft**を付けたり外したりしている。
js側のコードのイメージはこんな感じである。

```js

function start(){
    var leftList1 = document.getElementsByClassName("left");
    for(var i = 0; i < leftList1.length; i++) {
        leftList1[i].classList.add('hurueruLeft');
    }
}
function stop(){
    var leftList1 = document.getElementsByClassName("left");
    for(var i = 0; i < leftList1.length; i++) {
        leftList1[i].classList.remove('hurueruLeft');
    }
}
```
## animation
次に問題の、animationである。
あ、じゃあこの辺のことについてはこのページがわかりやすいので見てくださーい。
[【CSS3】@keyframes と animation 関連のまとめ](https://qiita.com/7968/items/1d999354e00db53bcbd8)
と言ってしまえば終わりなのであるが、ここで私は何をしたかったかを少し説明しようと思う。

では、まずこの動画を見てくれ。[Bellini - Samba De Janeiro](https://www.youtube.com/watch?v=HAiHEQblKeQ)
これが「samba de janeiro」の動画なのだが、何か気づいたことはあるだろうか。
　
　
　
　
　
そう、BPMが133なのだ。
BPMとは曲のテンポのことである。
**私はこの動画を流しながら、サンバを踊る顔文字を見られるようにしたかったのである。**
このテンポで動かすようにCSSを設定しなければならない。

### keyframes の設定
以下がkeyframesの設定である。
keyframesによって、こんな感じに設定すると良いのである。
> 左手は中央→上→中央→下→中央...を繰り返す。

```css
@keyframes huruLeft {
    0% {transform: translateY(0px)}
    25% {transform: translateY(-10px)}
    50% {transform: translateY(0px)}
    75% {transform: translateY(5px)}
    100% {transform: translateY(0)}
}
```

別に知らなくても、こういう書き方するんだへぇ〜って直観的にわかってしまう。

### style 側で keyframes を参照

.hurueruLeftの説明を行う。

**animation** には keyframes で動きを指定し、動きの回数を指定することができる。
今回は infinite なので永遠に行い続ける。

**animation-duration** に、一連の動きを終えるまでの時間を書くことができる。
今回は samba de janeiro のテンポに合わせる。一連の動きは２拍かけて行いたい。
計算式は 60000ms(60x1000ms)/133*2 というわけで約 902ms である。
いくらか調べてみたのだが、animation-duration は ns では設定できないようだ。
ずっと再生していると小数点以下の誤差でずれてくるのが悲しいが、仕方ない。

要するにこうなる。
「hurueruLeft は huruLeft の動きを無限に続けて、
samba de janeiro の2拍分の902msかけて動きますよ」

```css

.hurueruLeft {
    animation: huruLeft infinite;
    animation-duration: 902ms;
}
```
というわけで左手の説明を終えたわけであるが、顔と右手にも同じような処理を良い感じに設定している。
ちなみに、右手の動きは左手の点対称とはなっていない。どうでもいいこだわりである。

faceの紹介を少ししよう。

### 世の中顔
```css
@keyframes huru {
    0% {transform: translateX(0px)}
    25% {transform: translateX(-1px) rotateZ(3deg)}
    50% {transform: translateX(0px)}
    75% {transform: translateX(1px) rotateZ(-3deg)}
    100% {transform: translateX(0)}
}
```

faceは少しだけ回転している。そして親要素の左右移動に加えてさらに微妙な移動をしている。
謎のこだわりポイントである。やっぱり顔は大切なのである。

## transition の話少し
親要素の動きが少し気持ち悪い。ぬるっとしている。
一つの動きに対しても、微妙な変化を持たせることができる。
説明が面倒なので、linear とか ease-in-out とか書いているところがそれだ。
この設定で「ぬるっ」って動いたり「ぐーーん」と動いたり、なんとなく見栄えが変わる。

[【CSS3】Transition（変化）関連のまとめ](https://qiita.com/7968/items/812d6a21fc4dd9ae9c75)

先ほど紹介した記事と同じ人がまとめてくださっている。本当にありがたいことである。
結構面白い。実際 css だけでこのようなぬるっとした動きが出来るのは驚きだった。
実際に自分でいじると、案外おおってなったりする。この辺も、謎にこだわった覚えがある。

## 墓
墓があるので探してみてほしい。

# まとめ

確か夜中に3、4時間ぐらいで作ったと記憶している。
こういうのじわじわ勉強しながら楽しいし、一旦思いついちゃうと寝れないものだ。

今の所、リズムよく気持ち悪い動きをする顔文字がいるくらいで面白いところがないので、
何かしらの付加要素で単体で見れるページにしたいと思っているが、特に案はない。
何かあればこっそり教えていただきたい。

# そして秋

研修も終わり、同期とサンバが踊れなくなって少し寂しくなりましたが、
最近はとても良い環境で仕事をさせていただいております。
家で開発したり、Qiitaにcontributeする気になってきたので、今後ともよろしくお願いします。

# 追記ing

３日ぐらいしてふと見てみるとForkされてて、Fork先ではこんなことになっていましたァ！w

## Vue.js を用いた顔文字のコンポーネント化
かの有名なサンバ踊りCSSに機能追加してみました - Aikの技術的な進捗部屋　
 https://aik0aaat.hatenadiary.jp/entry/2019/09/09/195131

こちらの方です、是非。あと、命名規則に突っ込まれてて素直に草です。
1人で適当に作るときは適当に変な変数作るの楽しいですよね。会社ではちゃんと付けています。

というわけでQiitaに投稿するとこんなこともあるんですね、ありがとうございます。
励みに何かを生み出していきたいですね。