尝试使用 JavaScript 触发 CSS 转换

Trying to trigger a CSS transition using JavaScript

玩 JavaScript 和 CSS 转换,我试图删除 CSS class 在使用 JavaScript 和 innerHTML.

动态插入 div 之后

我真的很惊讶 CSS 与蓝色 div 的不透明度相关的过渡没有按照我想要的方式触发(在 Safari 下工作,在 [=30 下随机工作=], 在 Firefox Dev Edition 下不工作)。有人可以解释这种现象吗?

我不确定为什么它的工作方式与红色 div 不同。也许我不知道浏览器如何处理 innerHTML?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Having fun with JS</title>
    <style>
        .std {
            width:100px;
            height:100px;
            opacity: 1;
            transition: opacity 5s;
        }

        .std--hidden {
            opacity: 0;
        }

        .std--red {
            background-color: red;
        }

        .std--blue {
            background-color: blue;
        }
    </style>
</head>
<body>
<button>click here</button>
<div class='std std--red std--hidden'></div>
<div class='insert-here'>
</div>
<script>
    // let a chance to the browser to trigger a rendering event before the class is toggled
    // see 
    setTimeout(function() {
        // everything works fine for the red div
        document.querySelector('.std--red').classList.toggle('std--hidden');
    }, 0);


    document.querySelector('button').addEventListener('click', function(e) {

        var template = `<div class='std std--blue std--hidden'></div>`;
        document.querySelector('.insert-here').innerHTML = template;

        setTimeout(function() {
            // Why does the CSS transition seems to be triggered randomly ?
            // well more exactly
            // - it works under my Safari
            // - it does not work under my FirefoxDeveloperEdition
            // - it works randomly under my Google Chrome
            document.querySelector('.std--blue').classList.toggle('std--hidden');
        }, 0);

    });
</script>
</body>
</html>

编辑

所以我刚刚阅读了 CSS transitions specs 并找到了这个

This processing of a set of simultaneous style changes is called a style change event. (Implementations typically have a style change event to correspond with their desired screen refresh rate, and when up-to-date computed style or layout information is needed for a script API that depends on it.)

这可以作为某种解释吗? setTimeout 0 在某些浏览器上是否太快以至于他们没有时间计算样式差异,因此不会触发样式更改事件?事实上,如果使用更长的 setTimeout(比如,~16.6666,猜测 1/60 的刷新率......)它似乎无处不在。有人可以证实吗?

您必须为超时设置一个值,以便为要在 DOM 中插入的元素提供时间(调用 document.querySelector 之前必须存在)

setTimeout(function() { document.querySelector('.std--blue').classList.toggle('std--hidden')},100);

你不需要第一次超时

onload = function() {
document.querySelector('.std--red').classList.toggle('std--hidden');

 document.querySelector('button').addEventListener('click', function(e) {
   var template = "<div class='std std--blue std--hidden'></div>";
   document.querySelector('.insert-here').innerHTML = template;
   setTimeout(function() { document.querySelector('.std--blue').classList.toggle('std--hidden')},100);
    });
}
 .std {
            width:100px;
            height:100px;
            opacity: 1;
            transition: opacity 5s;
        }

        .std--hidden {
            opacity: 0;
        }

        .std--red {
            background-color: red;
        }

        .std--blue {
            background-color: blue;
        }
<button>click here</button>
<div class='std std--red std--hidden'></div>
<div class='insert-here'>
</div>

看来您必须通过引用样式来触发转换。我只是简单地添加了这一行(即使是 console.log 也可以)

document.querySelector('.std.std--blue').style.width = '20';

这里有效:jsfiddle

注意:我使用的是 FirefoxDeveloperEdition。

我已经关注了这个 solution:

CSS Transitions do not animate when you add or remove class, It will only animate when you change the CSS properties.

完成脚本

<script>

setTimeout(function() {
    // everything works fine for the red div
    document.querySelector('.std--red').classList.toggle('std--hidden');
}, 0);


document.querySelector('button').addEventListener('click', function(e) {

    var template = `<div class='std std--blue std--hidden'></div>`;
    document.querySelector('.insert-here').innerHTML = template;
    document.querySelector('.std.std--blue').style.width = '20';
    setTimeout(function() {

        document.querySelector('.std.std--blue').style.width = '100';
        document.querySelector('.std--blue').classList.toggle('std--hidden');
    }, 0);

    });
</script>

我想我找到了答案,请参阅 CSS 3 transition spec:

Since this specification does not define when a style change event occurs, and thus what changes to computed values are considered simultaneous, authors should be aware that changing any of the transition properties a small amount of time after making a change that might transition can result in behavior that varies between implementations, since the changes might be considered simultaneous in some implementations but not others.

我尝试添加一点延迟让浏览器注意到样式差异并且它始终如一地工作。似乎某些浏览器执行 setTimeout 0 的速度确实比其他浏览器快 :-)

    setTimeout(function() {
        document.querySelector('.std--blue').classList.toggle('std--hidden');
    }, 17);

要触发转换,您真的不需要 class 来切换。这很重要,因为您可能无法预先设置 classes 动态切换。换句话说,您可能只需要更改一些 CSS 属性即可触发转换。但是是的......你需要满足以下条件;

  1. 为了使您的 <div id="blue"></div> 元素具有动画效果,它必须带有 std class,其中定义了 transition。所以首先我们应该像 blue.classList.add("std");
  2. 您需要异步执行任务。异步刷新 DOM 最好由 requestAnimationFrame() 函数完成。

var blue = document.getElementById("blue");
blue.classList.add("std");
blue.style.backgroundColor = "blue";
blue.style.opacity         = 0;

document.querySelector('button')
        .addEventListener( 'click'
                         , _ => requestAnimationFrame(_ => blue.style.opacity = 1)
                         );
.std { width:100px;
       height:100px;
       opacity: 1;
       transition: opacity 5s;
}
.std--red { background-color: red;}
<button>click here</button>
<div class='std std--red'></div>
<div id="blue"></div>