Chrome浏览器中CSS渐变效果无法正常工作

4
我用JavaScript编写了这个函数:
function unhide(el, dur = 300, display = "block") {
    el.style.display = display;
    el.style.transitionDuration = dur + "ms";
    el.style.opacity = 1;
}

由于某种原因,这在Chrome中无法正常工作。

我记得曾经遇到过这样的问题,因为浏览器没有原子地应用由Javascript编写的CSS。

所以,我尝试在显示更改后放置一个断点:

function unhide(el, dur = 300, display = "block") {
    el.style.display = display;
●   el.style.transitionDuration = dur + "ms";
    el.style.opacity = 1;
}

这样就解决了问题。

在FireFox中也会出现相同的问题,但在Microsoft Edge中不会。

我该如何解决这个问题?

有没有一种方法可以强制浏览器先应用显示,然后再应用不透明度?


我刚刚考虑使用setTimeout为了设置不透明度,因为显示不是原子性应用的),然而,这似乎是一种混乱/低效的 hack。


4
@Rohit,我不想导入jQuery库来解决这个微小的问题。 - Tobiq
@Metis 我不是在试图转换它... - Tobiq
如果我能应用一组原子样式,然后只有一个浏览器回流,那么我就不会说有问题,只是我的个人看法。Timeout(0) 是正确的方法。 - deblocker
是的,它是0。(这就是我能看到元素出现的方式,只是没有淡入效果)。 - Tobiq
Freeman的答案设置了一个超时,等待显示切换然后它转换不透明度。它不会尝试同时转换两个属性。尝试将显示属性作为函数的一部分进行转换通常会导致转换问题。 - Scott
显示剩余12条评论
2个回答

2

使用requestAnimationFrame实现的最小化实现

function unhide(el, dur = 1000, display = "block") {
    console.log("opacity when display none: ", getComputedStyle(mrHyde, null).opacity);
    el.style.display = display;
    console.log("opacity when display block: ", getComputedStyle(mrHyde, null).opacity)
    el.style.transitionDuration = dur + "ms";
    requestAnimationFrame(() => el.style.opacity = 1);
}

const mrHyde = document.getElementById("unhideMe");
unhide(mrHyde);
#unhideMe {
  display: none;
  opacity: 0;
}
<div id="unhideMe">Mr. Hyde</div>

编辑 我用requestAnimationFrame 替换了 setTimeout。最终结果相同,但我觉得requestAnimationFrame更适合这个目的。

编辑2 实际上,这种行为已经被报告为bug。线程中的最后一条评论提出了一个假设,我也在推测。也许当元素处于display: none时,浏览器会“丢弃”opacity的数值。这意味着设置opacity: 1不会触发CSS过渡,因为过渡仅适用于明确定义的样式属性值。 在下一个事件循环中,浏览器将为元素定义opacity值,因为它现在处于display: block状态。

我通过记录元素在display: none和切换到display: block后的计算样式值来证明这个假设。这两个值都是一个明确定义的数字0,所以这与假设相矛盾。

PS:http://caniuse.com/#feat=requestanimationframe 截至2017年,涵盖requestAnimationFrame的范围似乎相当可接受,包括IE > 9版本。


它在SO上运行正常。我会在我的代码中再试一次。 - Tobiq
是的,经过简化版本测试似乎可以正常工作。也许您在当前环境中遇到了一些阻碍(CSS或JS)。 - Freeman Lambda
我认为,与其使用已经提出的解决方法,不如解释一下为什么会出现这种情况,因此获得了3个赞。 - deblocker
@deblocker 你说得对,这不是一个“被接受的答案”。这个答案旨在提供一个最小的工作解决方案,而不需要使用 jsfiddle 或其他外部沙盒。 - Freeman Lambda
@FreemanLambda:别担心,你的回答是关于“如何解决这个问题”的,这最终是最有用的事情... - deblocker
1
Freeman,requestAnimationFrame 确实起作用了,但是我担心它的兼容性... 其实,谁在乎 ie10< 呢? - Tobiq

2

根据理论,已经注意到浏览器会将JS应用的CSS修改分组在一起。


有没有办法强制浏览器先应用display,然后再应用opacity?

有。添加以下代码:

el.offsetWidth;

在这两个CSS修改之间加入代码,强制浏览器重新呈现页面的CSS。

var el = document.getElementById("hidden");
unhide(el);

function unhide(el, dur = 300, display = "block") {
    el.style.display = display;
    el.style.transitionDuration = dur + "ms";
    el.offsetWidth;
    el.style.opacity = 1;
}
<div id="hidden" style="display: none; opacity: 0;">Unhidden</div>


不知道这个。谢谢! - leonheess

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接