为什么svg上的转换没有延迟地在DOMContentLoaded上工作?

时间:2017-03-19 20:07:38

标签: javascript html css svg css-transitions

我有一个svg,其上设置了过渡。现在当我向它添加一个具有一些属性变化的类时,只有在DOMContentLoaded事件和addclass事件之间添加延迟时才会发生转换。这是两个例子,第一个没有延迟第二个有无限小延迟:

没有延迟:

! function() {
  window.addEventListener('DOMContentLoaded', function() {
    var logo2 = document.querySelector("svg");
    logo2.classList.add('start');
  });
}();
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104.75 32.46">
            <defs>
                <style>
                polygon {
                    fill: red;
                    transition: opacity 3s ease-out, transform 3s ease-out;
                    opacity: 0;
                }

                .start polygon {
                	opacity: 1;
                }
				
				#A1 polygon {
					transform: translate(100px, 100px);
					transition-delay: 1s;
				}

				/*styles after animation starts*/
				.start #A1 polygon {
					transform: translate(0px, 0px);						
				}


            </style>
            </defs>
            <title>Logo</title>
            <g id="A1">
                
                <polygon  class="right" points="0.33 31.97 0.81 26.09 13.61 3.84 13.13 9.72 0.33 31.97" />
            </g>
            </svg>

延迟:

! function() {
  window.addEventListener('DOMContentLoaded', function() {
    var logo2 = document.querySelector("svg");
    setTimeout(function(){
       logo2.classList.add('start');
    },0);
  });
}();
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104.75 32.46">
            <defs>
                <style>
	                polygon {
	                    fill: red;
	                    transition: opacity 3s ease-out, transform 3s ease-out;
	                    opacity: 0;
	                }

	                .start polygon {
	                	opacity: 1;
	                }
					
					#A1 polygon {
						transform: translate(100px, 100px);
						transition-delay: 1s;
					}

					/*styles after animation starts*/
					.start #A1 polygon {
						transform: translate(0px, 0px);						
					}


                </style>
            </defs>
            <title>Logo</title>
            <g id="A1">
                
                <polygon  class="right" points="0.33 31.97 0.81 26.09 13.61 3.84 13.13 9.72 0.33 31.97" />
            </g>
            </svg>

正如你在第二个例子中所看到的,我添加了0秒的延迟,但它导致动画工作,为什么?

更新1:嗯......我们都错了: - )

我在没有DOMContentLoaded的情况下尝试了相同的代码,没有延迟。它仍然没有延迟添加转换:

! function() {
 
    var logo2 = document.querySelector("svg");
    logo2.classList.add('start');

}();
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104.75 32.46">
            <defs>
                <style>
                polygon {
                    fill: red;
                    transition: opacity 3s ease-out, transform 3s ease-out;
                    opacity: 0;
                }

                .start polygon {
                	opacity: 1;
                }
				
				#A1 polygon {
					transform: translate(100px, 100px);
					transition-delay: 1s;
				}

				/*styles after animation starts*/
				.start #A1 polygon {
					transform: translate(0px, 0px);						
				}


            </style>
            </defs>
            <title>Logo</title>
            <g id="A1">
                
                <polygon  class="right" points="0.33 31.97 0.81 26.09 13.61 3.84 13.13 9.72 0.33 31.97" />
            </g>
            </svg>

我还注意到jQuery不会导致重排。下面是一个内联jquery代码的示例,在加载CSSOM之前仍然不会触发ready函数。如果我们有外部jquery,那么在CSSOM准备就绪之后就会触发就绪事件,而不是内联jquery。我已经达成的理解是CSSOM在渲染html dom后需要几毫秒。所以直到下载外部jquery CSSOM就准备好了。 DOMContentLoaded根本不关心是否加载了样式表,也就是说它不关心CSSOM是否准备就绪。

2 个答案:

答案 0 :(得分:7)

因为那是DOMContentLoaded的作用:当解析DOM时,但在CSSOM之前(因此在应用样式之前)它会触发。

如果您不想等待load活动,
一种方法是通过在任何文档的元素(例如offsetXXX)上调用<body>属性来强制浏览器在脚本执行(同步)之前进行绘制:< / p>

&#13;
&#13;
! function() {
  window.addEventListener('DOMContentLoaded', function(){
    document.body.offsetTop; // force a CSS repaint
    var logo2 = document.querySelector("svg");
    logo2.classList.add('start');
  });
}();
&#13;
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104.75 32.46">
  <defs>
    <style>
      polygon {
        fill: red;
        transition: opacity 3s ease-out, transform 3s ease-out;
        opacity: 0;
      }
      .start polygon {
        opacity: 1;
      }
      #A1 polygon {
        transform: translate(100px, 100px);
        transition-delay: 1s;
      }
      /*styles after animation starts*/
      .start #A1 polygon {
        transform: translate(0px, 0px);
      }
    </style>
  </defs>
  <title>Logo</title>
  <g id="A1">
    <polygon class="right" points="0.33 31.97 0.81 26.09 13.61 3.84 13.13 9.72 0.33 31.97" />
  </g>
</svg>
&#13;
&#13;
&#13;

答案 1 :(得分:4)

  

正如您在第二个示例中所看到的,我添加了0秒的延迟,但   导致动画有效,为什么?

由于DOMContentLoaded事件触发时尚未加载CSS对象模型

  

初始HTML文档具有时触发DOMContentLoaded事件   已完全加载和解析,无需等待样式表,   图像和子帧完成加载。一个非常不同的事件负载   应该仅用于检测完全加载的页面。这是一个令人难以置信的   使用负载的流行错误DOMContentLoaded会更多   适当的,所以要小心。

     

https://developer.mozilla.org/en/docs/Web/Events/DOMContentLoaded

因此,添加css类不会运行动画。

setTimeOut方法是一个javascript事件,一旦被触发(即使有0次),它将被添加到当前浏览器执行队列的末尾(在你的情况下将在加载CSS模型后添加) )。因此,动画将正常启动。

更新

  

但是加载CSSOM后jquery domready会激活。所有这些也是如此   SO上的帖子在技术上是不正确的?

domready使用DOMContentLoaded所以从理论上说,他们的行为方式相同。

  

之前执行延迟脚本标记(内联或外部)    CSSOM已加载?

defer属性延迟的脚本在DOMContentLoaded被触发之前执行。所以答案是肯定的。