技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

要素追加をCSSアニメーションで実装したい

何がしたいって、スライドインアウトしたい。
原理的にはスライドインさえできれば、スライドアウトは似たようなものだろう。

まずはアニメーションできるようにしようか。とりあえずはマウスを上に置いたらアニメーションで色を変える。

.block {
    display: inline-block;
    border-radius: .5em;
    padding: .5em 1em;
}

.component {
    -webkit-transition: all 0.5s ease;
    -opera-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    transition: all 0.5s ease;
}

.component:hover {
    background-color: #ccc;
}
<div class="block component">シンプル要素</div>

これでマウスを置いた瞬間にアニメーションで背景が変わるようになる。

transitionHTML5 に追加されており、2015/5/23 時点においては各ベンダープレフィックスが必要になる。
設定している値は、先頭から順に「アニメーションするcss値(all で全部)」「アニメーションにかかる時間」「アニメーション変化のパターン」がある。
まぁ詳細はググればok

ここで気をつけなければならないのは、初期状態を component で定義しており、その後に component:hover を追加適用した場合の変化をアニメーションしている点である。
何が言いたいかというと、component だけではアニメーションにならないということ。

これを要素追加に適用する場合は、追加時のcss と、追加後に適用するcss の二つを連続して適用する必要がある。
jQuery にはそんなことをせずともアニメーションはあるが、敢えて css3 で適用する。(とはいえ jquery は使う)

<script type="text/javascript">
    $(document).ready(function() {
        var appendNo = 1;
        $("#append").click(function() {
            $("#append").after('<div class="block component">追加要素 ' + appendNo + '</div>');
            appendNo = appendNo + 1;
        });

        $("#content").on("DOMNodeInserted", function(evt){
            var target = $(evt.target)
            setTimeout( function() {
                target.addClass("loaded");
            }, 10 );
        });
    });
</script>

<div id="content">
    <button id="append">シンプルボタン</button>
</div>

DOM が追加された際に DOMNodeInserted イベントが発生するので、その 10 ミリ秒後に loaded クラスを追加する。
ここでディレイを入れずに loaded を追加してしまうと、アニメーションせずにアニメーション完了後の姿が表示されてしまう。
別スレッドで追加することに意味があるらしい。

.block {
    display: inline-block;
    border-radius: .5em;
    padding: .5em 1em;
}

.component {
    -webkit-transition: all 1.5s ease;
    -opera-transition: all 1.5s ease;
    -o-transition: all 1.5s ease;
    transition: all 1.5s ease;
    opacity: 0;
}

.component.loaded {
    background-color: #ccc;
    opacity: 1;
}

その上で CSS を上記のように定義する。
これで追加した瞬間にアニメーションが開始するようになる。

ではスライドで追加してみよう。

.block {
    display: inline-block;
    border-radius: .5em;
    padding: .5em 1em;
    border: solid 1px #ccc;
}

.component {
    -webkit-transition: all 1.5s ease;
    -opera-transition: all 1.5s ease;
    -o-transition: all 1.5s ease;
    transition: all 1.5s ease;
    opacity: 0;

    transform:translateX(-50px);
}

.component.loaded {
    opacity: 1;
    transform:translateX(0);
}

こう変更する。
border 付けたのはわかりやすいように。transform が css3 で追加されているので、初期位置を -50px 左に指定して、その跡 0 に戻す。
このスタイルのいいところは、事実上のボックスは最終位置にありながら、表示だけ変更できる。

ただし、要素が追加された瞬間にそれまであった要素は右に瞬間移動せざるを得ない。
避けるために width もいじるとわかるが、width:auto ではアニメーションできない。

真面目にやりたければ、全部の要素を固定サイズにして position:absolute の上、top/left を設定するしかない。
知っているとは思うが、position:relative なり position を親要素で指定すると、その子要素の position:absolute は親要素を起点とした絶対位置指定に変わる。

後は根性で座標計算するんだっちゃw