使用暂时禁用的CSS转换在JavaScript中更改HTML元素的样式不可靠 [英] Changing an HTML element's style in JavaScript with its CSS transition temporarily disabled isn't reliably functioning

查看:74
本文介绍了使用暂时禁用的CSS转换在JavaScript中更改HTML元素的样式不可靠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我正在为一个网站制作一个动画,其中涉及到两个元素在一段时间内的位置发生了变化,并且通常会重置为初始位置。一次只能看到一个元素,一切都应该尽可能平稳地运行。



在你问之前,一个纯CSS的解决方案是不可能的,因为它是动态的生成并且必须同步。为了这个问题,我将使用一个非常简化的版本,它只包含一个向右移动的盒子。我将只提到后面的例子,除非明确指出这个问题的其余部分是为了让事情变得简单。



无论如何,移动由CSS 处理,过渡属性被设置,以便浏览器可以为此付出沉重的代价。然后,必须彻底消除此转换,以立即重置元素的位置。这样做的显而易见的方法是,当它需要再次移动时,这样做就可以重新应用 transition ,这也是即时的。但是,这不起作用。不完全的。我会解释一下。



在这个问题的结尾处或链接的JSFiddle中查看JavaScript,您可以看到我正在做的事情,但setTimeout增加了25ms之间的延迟。这样做的原因是(如果没有延迟(这是我想要的)或非常短的延迟,这个元素可能会间歇性地或持续地保持原位,而不是预期的效果。延迟越高,工作的可能性越大,但在我的实际动画中,这会导致较小的抖动,因为动画分两部分工作,并且不会延迟。

这看起来像是一种可能是浏览器错误的东西,但我已经在Chrome,Firefox 52和当前版本的Firefox上测试过,所有这些都有类似的结果。我不确定该从哪里出发,因为我无法在任何地方或任何解决方案/解决方法中找到此问题。如果有人能够找到一种方法使得这个工作按预期可靠工作,那将是非常值得赞赏的。 :)




这里是JSFiddle页面,其中包含我的意思。



标记和代码也粘贴在这里:



var box = document.getElementById(box); // Reduce this值或将其设置为0(我//要摆脱完全超时)/ /它只会正常工作/ / discontinuous.var延迟= 25; setInterval(function(){box.style.transition =none; box.style.left =1em; setTimeout(function(){box.style.transition =1s linear; box.style.left =11em;},delay);},1000);

#box {width:5em;身高:5em;背景颜色:青色;位置:绝对; top:1em; left:1em;}

< div id =box >< / div>

解决方案 div>

强制DOM在重置之后设置新的转换之前重新计算自己。这可以通过读取盒子的偏移量来实现,例如:

  var box = document.getElementById(box); setInterval(function(){box.style.transition =none; box.style.left =1em; let x = box.offsetLeft; //读取定位值会强制DOM重新计算更改后的所有位置box.style.transition =1s linear; box.style.left =11em;},1000);  

body {background-color:rgba(0,0,0,0);}#box {width: 5em的;身高:5em;背景颜色:青色;位置:绝对; top:1em; left:1em;}

< div id =box >< / div>

$ b

另请参阅jsFiddle上的工作演示



通常DOM在设置其属性之前不会更新,直到脚本完成。然后重新计算和渲染DOM。但是,如果在更改后读取DOM属性,则会立即强制执行重新计算。



没有超时(和属性读取)会发生什么情况,首先将 style.left 值更改为1em,然后立即到11em。在脚本完成之后进行转换,并看到最后的设置值(11em)。但是如果你在这些变化之间读到一个位置值,那么转换就有了新的价值。

Currently I am working on an animation for a website which involves two elements having their position changed over a period of time and usually reset to their initial position. Only one element will be visible at a time and everything ought to run as smoothly as possible.

Before you ask, a CSS-only solution is not possible as it is dynamically generated and must be synchronised. For the sake of this question, I will be using a very simplified version which simply consists of a box moving to the right. I shall be referring only to this latter example unless explicitly stated for the remainder of this question to keep things simple.

Anyway, the movement is handled by the CSS transition property being set so that the browser can do the heavy lifting for that. This transition must then be done away with in order to reset the element's position in an instant. The obvious way of doing so would be to do just that then reapply transition when it needs to get moving again, which is also right away. However, this isn't working. Not quite. I'll explain.

Take a look at the JavaScript at the end of this question or in the linked JSFiddle and you can see that is what I'm doing, but setTimeout is adding a delay of 25ms in between. The reason for this is (and it's probably best you try this yourself) if there is either no delay (which is what I want) or a very short delay, the element will either intermittently or continually stay in place, which isn't the desired effect. The higher the delay, the more likely it is to work, although in my actual animation this causes a minor jitter because the animation works in two parts and is not designed to have a delay.

This does seem like the sort of thing that could be a browser bug but I've tested this on Chrome, Firefox 52 and the current version of Firefox, all with similar results. I'm not sure where to go from here as I have been unable to find this issue reported anywhere or any solutions/workarounds. It would be much appreciated if someone could find a way to get this reliably working as intended. :)


Here is the JSFiddle page with an example of what I mean.

The markup and code is also pasted here:

var box = document.getElementById("box");
//Reduce this value or set it to 0 (I
//want rid of the timeout altogether)
//and it will only function correctly
//intermittently.
var delay = 25;

setInterval(function() {
  box.style.transition = "none";
  box.style.left = "1em";

  setTimeout(function() {
    box.style.transition = "1s linear";
    box.style.left = "11em";
  }, delay);
}, 1000);

#box {
  width: 5em;
  height: 5em;
  background-color: cyan;
  position: absolute;
  top: 1em;
  left: 1em;
}

<div id="box"></div>

解决方案

Force the DOM to recalculate itself before setting a new transition after reset. This can be achieved for example by reading the offset of the box, something like this:

var box = document.getElementById("box");

setInterval(function(){
      box.style.transition = "none";
      box.style.left = "1em";
      let x = box.offsetLeft; // Reading a positioning value forces DOM to recalculate all the positions after changes
      box.style.transition = "1s linear";
      box.style.left = "11em";  
    }, 1000);

body {
  background-color: rgba(0,0,0,0);
}

#box {
  width: 5em;
  height: 5em;
  background-color: cyan;
  position: absolute;
  top: 1em;
  left: 1em;
}

<div id="box"></div>

See also a working demo at jsFiddle.

Normally the DOM is not updated when you set its properties until the script will be finished. Then the DOM is recalculated and rendered. However, if you read a DOM property after changing it, it forces a recalculation immediately.

What happens without the timeout (and property reading) is, that the style.left value is first changed to 1em, and then immediately to 11em. Transition takes place after the script will be fihished, and sees the last set value (11em). But if you read a position value between the changes, transition has a fresh value to go with.

这篇关于使用暂时禁用的CSS转换在JavaScript中更改HTML元素的样式不可靠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆