尝试使用 JavaScript 触发 CSS 转换

Posted

技术标签:

【中文标题】尝试使用 JavaScript 触发 CSS 转换【英文标题】:Trying to trigger a CSS transition using JavaScript 【发布时间】:2016-06-18 17:16:13 【问题描述】:

在玩 javascript 和 CSS 过渡时,我尝试删除一个 CSS 类 在使用 JavaScript 和 innerhtml 动态插入 div 之后。

我很惊讶与蓝色 div 的不透明度相关的 CSS 过渡没有按照我想要的方式触发(在 Safari 下工作,在 Chrome 下随机工作,在 Firefox 开发版下不工作)。有人能解释一下这种现象吗?

我不确定为什么它的工作方式与红色 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 http://***.com/a/4575011
    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 并找到了这个

对一组同时进行的样式更改的处理称为 样式更改事件。 (实现通常会改变风格 事件以对应于他们所需的屏幕刷新率,以及何时 脚本需要最新的计算样式或布局信息 依赖它的 API。)

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

【问题讨论】:

使用setTimeout有什么意义?它什么也没做。也许尝试删除它们,看看会发生什么? 是的,它很有用,在浏览器首次渲染 DOM 之后,它会将删除 css 类的代码排入队列 尝试删除您在var template 中插入内部 HTML 元素的反引号。而是看到添加双引号“” oooh...那个反引号没有做任何事情...您可能应该使用双引号(")作为外部和单引号(')作为class= 反引号对应一个 ES6 模板字符串。 【参考方案1】:

要触发转换,您实际上并不需要一个类来切换。这很重要,因为您可能无法动态设置类以预先切换。换句话说,您可能只需要更改一些 CSS 属性来触发转换。但是是的……您需要满足以下条件;

    为了使您的&lt;div id="blue"&gt;&lt;/div&gt; 元素具有动画效果,它必须带有定义transitionstd 类。所以首先我们应该像blue.classList.add("std"); 您需要异步执行任务。异步刷新 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>

【讨论】:

【参考方案2】:

我想我找到了答案,见CSS 3 transition spec:

由于本规范未定义何时发生样式更改事件 发生,因此计算值的变化被考虑 同时,作者应该意识到,改变任何 进行更改后一小段时间的转换属性 这可能会导致行为在 实施,因为这些变化可能被认为是同时在 一些实现,但不是其他的。

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

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

【讨论】:

【参考方案3】:

您必须为超时设置一个值,以便为元素插入 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>

【讨论】:

抱歉,我不能接受您的回答,因为它没有回答问题。我知道我可以改变延迟,我只是不明白为什么它在第二种情况下不起作用。 如果您尝试在 jsfiddle 之外运行代码(在浏览器中打开 HTML),如果您不放置 setTimeout,您会看到第一个动画吗?我没有。 是的代码在文档加载上运行,在 IE11、Firefox、Chrome 和 Chrome Canary 中测试 在我的电脑上,它在 Safari 版本 9.0.3 (11601.4.4) 下运行,但在 Chrome 版本 48.0.2564.116(64 位)下随机运行,在 Firefox 开发版 46.0a2 下无法运行(2016-03-04)。 :-( 尝试将您的代码封装在事件监听器中 onload = function() //code 【参考方案4】:

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

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

它在这里工作:jsfiddle

注意:我正在使用 FirefoxDeveloperEdition。

我关注了这个solution:

CSS 过渡不会在您添加或删除类时动画,它只会在您更改 CSS 属性时动画。

完整的脚本

<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>

【讨论】:

在 fiddle(或类似的)之外直接在浏览器中尝试,它对我不起作用。但它可以在 fiddle、codepen 等内部工作...... 不是这样,第一个动画被触发了。 您的代码似乎没有回答我关于为什么它适用于红色 div 而不适用于蓝色 div 的问题? CSS 过渡在您添加或删除类时不会动画,它只会在您更改 CSS 属性时动画。我也在答案中添加了它。

以上是关于尝试使用 JavaScript 触发 CSS 转换的主要内容,如果未能解决你的问题,请参考以下文章

如何从 JavaScript 设置和触发 css 转换

在 JavaScript 中触发 CSS 动画

普通 javascript 触发 css 淡出,ajax 加载内容,使用 CSS 淡入

如何使用 Javascript 键盘事件触发 CSS Sprite 动画

从 HTML、CSS、JS 转换为 JSX、CSS、JS 时,如何在 react 中链接我的 javascript 文件?

页面加载时触发CSS转换属性[重复]