`transform:rotateY`使用のフリップアニメーションについて、Edgeで残像が残る

transform:rotateYを使用してフリップアニメーションを実装したところ、Microfost Edgeで残像が残る現象に遭遇。

Edgeで残像が残る様子
Edgeで残像が残る様子

この他にも、Edgeでのみアニメーションがぎこちない(滑らかではない)というのもありますが、上述の現象から比べればまだ些事かと。

再現環境

<div class="container w-100">
    <div class="row">
        <div class="col-sm-6 col-md-4 item">
            <div class="item_card">
                <div class="item_imgWrapper">
                    <img src="https://placehold.jp/320x320.png" class="d-block mx-auto">
                </div>
                <div class="item_descWrapper p-lg-4 p-3">
                    <h4 class="item_descTitle my-3 text-center">irrespective</h4>
                    <div class="item_description">
                        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
                    </div>
                </div>
            </div>
        </div>
        <div class="col-sm-6 col-md-4 item">
            <div class="item_card">
                <div class="item_imgWrapper">
                    <img src="https://placehold.jp/320x320.png" class="d-block mx-auto">
                </div>
                <div class="item_descWrapper p-lg-4 p-3">
                    <h4 class="item_descTitle my-3 text-center">introspective</h4>
                    <div class="item_description">
                        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
                    </div>
                </div>
            </div>
        </div>
        <div class="col-sm-6 col-md-4 item">
            <div class="item_card">
                <div class="item_imgWrapper">
                    <img src="https://placehold.jp/320x320.png" class="d-block mx-auto">
                </div>
                <div class="item_descWrapper p-lg-4 p-3">
                    <h4 class="item_descTitle my-3 text-center">inspective</h4>
                    <div class="item_description">
                        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

こんなHTMLで、

@charset "utf-8";

.item {
    padding-bottom: 30px;
}
.item img {
    width: 100%;
    height: auto;
    border-radius: 0;
}
.item_imgWrapper, .item_descWrapper {
    width: 100%;
    height: 100%;
    transition: 0.8s;
    position: absolute;
    top: 0;
    left: 0;
    backface-visibility: hidden;
}
.item_imgWrapper {
    transform: rotateY(0);
}
.item_descWrapper {
    transform: rotateY(180deg);
    background-color: #4c4c4c;
    color: #fff;
}
.item_descTitle {
    font-weight: normal;
}
.item_card {
    width: 100%;
    height: auto;
    position: relative;
    cursor: e-resize;
    perspective: 100rem;
    transition: 0.3s ease-out;
}
.item_card::before {
    content: "";
    display: block;
    padding-top: 100%;
}
.item_card:hover .item_imgWrapper, .item_card.activeClick .item_imgWrapper {
    transform: rotateY(-180deg);
}
.item_card:hover .item_descWrapper, .item_card.activeClick .item_descWrapper {
    transform: rotateY(0);
}

こんなcssを記述したところ、発生。

原因

原因はcssのperspectiveの指定のようです。

.item_card {
    /* 略 */
    perspective: 100rem;
    /* 略 */
}

サンプルコードだと上述の部分ですね。

この部分を削ると現象は発生しなくなりました。ただし、奥行きがなくなるのでフリップアニメーションの回転が平面的になってしまいます。

対処

bowserを使って「Edge以外のブラウザの場合のみperspectiveを指定する(=Edgeではperspectiveを指定しない)」ということで対処しました。

「原因」のところでも記述した通りフリップアニメーションの奥行きは犠牲になりますが、その影響範囲をEdgeのみとなるべく絞った形になります。

    <script src="https://code.jquery.com/jquery-3.4.1.min.js" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/bowser@2.7.0/es5.js"></script>
    <script src="./js/index.js"></script>

HTMLはbowserの読み込みと判定のスクリプトを追加。

$(() => {
    const browser = bowser.getParser(window.navigator.userAgent);
    const $body = $("body");
    if (browser.getBrowserName().indexOf('Edge') > -1) {
        //Edgeならば
        $body.addClass("msEdge");
    }
});

jQueryでサクッとbodyタグにmsEdgeクラスを付与するスクリプトを記述。

.item_card {
    width: 100%;
    height: auto;
    position: relative;
    cursor: e-resize;
    transition: 0.3s ease-out;
}
body:not(.msEdge) .item_card {
    /* Edgeでない場合のみ付与 */
    perspective: 100rem;
}

cssは親セレクタにbody:not(.msEdge)を記述することで、JavaScriptの記述と併せて「Edgeではない場合」と絞った形になります。

備考1 (Edgeの行く末)

Microsoft Edgeは上述記事の通り来月(2020/1/15)にレンダリングエンジンをChromiumに変更したバージョンをリリース予定にしており、レンダリングエンジンがEdgeHTMLである現行バージョン特有のバグはなくなると思われます(事実、dev版のEdgeでは今回の症状は発生しませんでした)。

したがって、あと1ヶ月足らずで変更されるものについて今更感がある(大掛かりな対応はしたくない)のですが、今回はこれで。

備考2 (css, 可変幅・高さの親要素に子要素をposition:absolute;指定して親要素の高さが潰れた場合の対処法)

上述のコードでさらっと使っているのですが、今回のカードはBootstrap4のグリッドに則っているのでカードの幅と高さは可変になっています。

このカードにアニメーションのためposition: absolute;を指定すると親要素の高さが潰れてしまいます。

対処法が上述の記事。

.item_imgWrapper, .item_descWrapper {
    /* 略 */
    position: absolute;
    top: 0;
    left: 0;
    /* 略 */
}
.item_card {
    width: 100%;
    height: auto;
    position: relative;
    /* 略 */
}
.item_card::before {
    /* 潰れた高さを戻す */
    content: "";
    display: block;
    padding-top: 100%;
}

今回はこのような使い方をしました。

この記事を書いた人

アバター

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。