使用字符串设置内联css过渡样式会更改真值。奇异的

时间:2014-07-24 20:15:12

标签: javascript html css css3

我有一个样式表,可以像这样设置一个css过渡属性(为了简洁省略了前缀版本):

transition: opacity 1s;

然后我在页面上有许多元素,我希望通过JavaScript修改每个元素的transition-delay属性,以产生交错效果。我正在使用jQuery:

$(element).css('transition-delay', delay + 's');

但是,上面的代码为元素添加内联transition-delay: Xs。相反,它导致:

<div style="transition: Xs;">

但这很好,因为它按预期工作。不知何故,浏览器知道transition: Xs真的意味着只需将transition-delay设置为X并保持其余部分完整。

然而:

如果我现在通过$(element).attr('style')获取该元素的内联样式,然后将其重新应用于元素$(element).attr('style', style),则HTML看起来完全相同,但现在转换完全覆盖了其他属性,并且实际上将元素的转换值设置为all Xs ease 0s

// HTML before - working
<div style="transition: Xs">

// then I do this
var style = $(el).attr('style');
$(el).attr('style', style);

// HTML after - broken!
<div style="transition: Xs">

演示

正是我所描述的JSFiddle:http://jsfiddle.net/7vp8m/4/

发生了什么事?

2 个答案:

答案 0 :(得分:5)

我认为只是写出问题并编写该演示真的帮助我找到答案:

HTML style属性实际样式。我们需要使用CSSStyleDeclaration对象

虽然似乎内联样式与style="..." HTML属性中包含的内容一样简单(正如我所假设的),但事实证明并非如此。在幕后,内联样式(以及所有其他样式)实际上由名为CSSStyleDeclaration的对象定义。 style属性中仅包含的字符串表示此对象,但不包含定义样式所需的所有信息。

这就是为什么设置`el.style =“width:100px;” 工作。来自MDN article on HTMLElement.style

  

除Opera中外,无法通过将字符串赋值给(只读)样式属性来设置样式,如elt.style =“color:blue;”。这是因为style属性返回CSSStyleDeclaration对象。相反,您可以设置样式属性,如下所示:

elt.style.color = "blue";  // Directly

var st = elt.style;
st.color = "blue";  // Indirectly

因此,这向我们展示了为什么$(el).attr('style', 'transition: Xs'); 按预期工作 - 这正是我遇到的问题。这样做修改底层的CSSStyleDeclaration对象,但并不总是按照我们想要的方式(因此我原来的问题)。

因此,解决方案是使用CSSStyleDeclaration提供的API。以下SO问题对我理解这个问题至关重要:JavaScript & copy style

复制CSSStyleDeclaration:

var originalStyle = el.cloneNode().style;

这里我们使用的是cloneNode()方法,因为否则(如果我们得到el.style)CSSStyleDeclaration对象是通过引用复制的,这不是我想要的,因为我将更改元素的内联样式然后我想要以后恢复原始样式。首先克隆元素允许我们获得CSSStleDeclaration的“新”副本,当我们更改元素el的内联样式时,它不会改变。

使用保存的CSSStyleDeclaration

替换当前内联样式
// first we need to delete all the style rules
// currently defined on the element
for (var i = el.style.length; i > 0; i--) {
    var name = el.style[i];
    el.style.removeProperty(name);
}

// now we loop through the original CSSStyleDeclaration 
// object and set each property to its original value

for (var i = originalStyle.length; i > 0; i--) {
    var name = originalStyle[i];
    el.style.setProperty(name,
        originalStyle.getPropertyValue(name),
        priority = originalStyle.getPropertyPriority(name));
}

演示

以下是我原始演示的更新,它实现了上述方法:http://jsfiddle.net/7vp8m/11/

答案 1 :(得分:0)

它打破了铬和新的&#34;歌剧,但没有在ff。在Maxthon中,它会在第一次停止并重新启动动画,然后运行良好。

正如你在http://jsfiddle.net/7vp8m/5所说的那样(幸运的是你解决了它),这是由于通过内联样式设置过渡延迟。

但是如果你强制引擎刷新css它会以某种方式工作(首先停止动画然后继续,播放动画更慢):http://jsfiddle.net/7vp8m/7/

function tick() {
    [...]
    $.each($('.test'), function(i, e){
        e.style.marginLeft = x + 'px'; // Trying with vanilla js but it is the same
        e.offsetHeight; // force the refresh. It moves again but bad
    });
    [...]
}

这也不起作用:http://jsfiddle.net/7vp8m/8/

$.each($('.test'), function (index, el) {
    var style = $(el).attr('style');
    style += '; transition-delay: '+delay + 's;'+
             '-webkit-transition-delay'+delay + 's;'
    $(el).attr('style', style);
    delay += 0.2;
});

它似乎是一个与转换延迟相关的webkit错误,但是Maxthon以类似的方式停止了动画,因此它可能是一个更通用的错误。

所以,如果它是一个bug,最好的选择是不要通过js使用属性transition-delay。