dav*_*ave 17 javascript css performance dom
我想在我的DOM中动态设置给定选择器的所有元素.我或多或少地看到了两种方式.对于下面的例子,我将使用一个p
元素及其text-align
属性,但我对这两种可能的方法的优缺点比我特别是文本对齐段落更有兴趣.
var nodes = document.getElementsByTagName('p');
Array.prototype.forEach.call (nodes, function (node) {
node.style.textAlign = "center";
});
Run Code Online (Sandbox Code Playgroud)
var sheet = (function() {
// Create the <style> tag
var style = document.createElement("style");
// WebKit hack :(
style.appendChild(document.createTextNode(""));
// Add the <style> element to the page
document.head.appendChild(style);
return style.sheet;
})();
sheet.insertRule("p { text-align: center; }");
Run Code Online (Sandbox Code Playgroud)
通常我会选择内联样式的路线,因为它看起来更简单,并确保样式更改将覆盖现有的样式表.但是对于我来说,有一种情况:有时不会覆盖样式表可能更可取,对于两个:修改一个style
元素可能比未知数量的p
元素更高效.但这只是我的假设.
性能方面,是否会出现这样的情况:将内联样式应用于每个单独的元素会比创建样式表更好?假设答案可能取决于我造型的元素数量,那么创建样式表会变得更有效吗?
编辑:为了澄清我为什么问这个问题,我会解释一下我为什么要问:我最近把一些JS黑客经常复制粘贴并在项目之间改编成一组可重复使用的CommonJS模块.在最大或最宽的度量可能会在窗口调整大小或其他触发器上发生变化的情况下,它们会执行诸如将给定选择器的所有元素设置为与最高或最宽集相同的高度或宽度的操作.
这是一篇关于它的博客文章:http://davejtoews.com/blog/post/javascript-layout-hacks
以下是模块的GitHub存储库:
此时,所有这些模块都使用内联样式,但我正在考虑将它们切换到样式表.我无法找到关于任何一种方法的利弊的好答案,所以我在这里发布了这个问题.
自React和JSX获得极大的欢迎以来,在过去的几年里,关于这一主题的争论很多.
我尝试了一些解决方案,所以我会在这里列出来.首先是一般性讨论..
CSS基本上是唯一支持使用全局命名空间的语言,这是人们摆脱直接CSS和重要总体框架的首要原因.使用flexbox,响应式布局可以在几行代码中完成,而不是整个网格系统,例如你可以使用像bootstrap这样的东西.
CSS解决了以可重用的方式向文档提供样式的问题,但随着应用程序变得越来越庞大和越来越复杂,并且包含了更多具有自己的CSS的第三方库,全局命名空间冲突的可能性几乎变得不可避免.这么多,以及一些不同的模式被创作和倡导,如BEM和SMACSS.
随之而来的反应使管理和创建可重用的内联样式变得相对简单.你可以使用所有的javascript,这意味着你可以使用像_.extend
或之类的东西覆盖样式Object.assign
.这样可以轻松共享包含组件及其样式的模块和包,并且不需要任何类型的样式加载器,例如使用时需要的样式webpack
.然而,并非所有玫瑰都是如此.事情是这样:hover
,其他的伪选择,和媒体查询在平原内嵌样式不被支持.
为了解决这些限制,开发人员实现了事件以触发样式更改,例如onmouseover
悬停,并挂钩到窗口调整大小事件以进行媒体查询.此后不久,一个用于标准化这些js事件的库,并定义了一个类似API的CSS,这个库被创建并获得了人气,称之为Radium
.在野外,镭也不公平(相信我,我试过).在大型应用程序中,在下载所有JS之后,所有媒体查询都无法执行,我不建议这样做!
这导致创建了一些采用不同方法的新工具.这些新一代工具使用JS中定义的样式,但生成CSS.这为您提供了内联样式的全部功能和CSS的全部功能.两全其美.哪个库最好可能取决于您的用例,但这些库包括Fela.js,Aphrodite和JSS.
我最喜欢的解决方案是Fela.js. 在fela.js.org上查看.Fela可能是您将获得的最佳性能,并不是特定于任何特定框架.据说它与React和React Native配合得很好.它有一些简洁的功能,例如允许您从样式中访问道具.您renderer
在页面的头部设置了一个.Fela最适合SSR,但也可以根据您的需要纯粹为客户端工作.使用SSR时,您可以获得超快的页面加载,因为Fela优化了您写入原子css类的样式,并在初始请求时将它们发送回客户端.
如果您担心获得最快的页面,这些工具是惊人的.您可以轻松地完成困难的模式,例如关键路径css优化,其中必要的样式作为初始HTTP请求的一部分返回,而不是指向也必须下载的外部工作表的链接.
最后,我不得不提到CSS模块.这些确实创建了一个外部样式表,但允许您仍然为每个模块配置命名空间CSS.这允许您编写真正的CSS或SASS等,但带来额外的设置开销.例如,在webpack中,您需要使用假样式加载器和文本提取工具的组合来创建.css文件.
对于您的问题,我没有一个很好的一般性答案(并且不确定是否有一个答案),但是我已经使用开发工具时间轴对您发布在Chrome 57.0.2987.98 Beta中的示例进行了一些实验。
这是在单个框架中完成的工作的细分,该框架使用内联样式(左)和动态样式表(右)更新了10,000个<p>
元素:
为了进行比较,以下是使用100个<p>
元素进行的同一测试的结果:
总而言之,对于少量元素,差异可以忽略不计。对于大量元素,使用内联样式时,浏览器会花费更多时间编写脚本(这是可以预料的,因为存在沉重的循环)并重新计算样式(我认为这可以解释为浏览器必须解析一种样式每个元素而不是一个通用样式规则)。
所有其他步骤大约花费相同的时间。特别是,使用内联样式时,绘制时间不会增加。
作为参考,我使用了以下测试页。
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<button id="add-stylesheet">Stylesheet</button>
<button id="add-inline-styles">Inline</button>
<script type="text/javascript">
let stylesheet = document.getElementById('add-stylesheet');
let inline = document.getElementById('add-inline-styles');
stylesheet.addEventListener('click', addStylesheet);
inline.addEventListener('click', addInlineStyles);
function addStylesheet() {
let style = document.createElement("style");
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
style.sheet.insertRule('p { text-align: center }', 0);
}
function addInlineStyles() {
let nodes = document.getElementsByTagName('p');
for (let node of nodes) {
node.style.textAlign = 'center';
}
}
// initialize <p> elements
init(10000);
function init(numElements) {
for (let i = 0; i < numElements; ++i) {
let p = document.createElement('p');
p.innerText = 'testing'
document.body.appendChild(p);
}
}
</script>
</html>
Run Code Online (Sandbox Code Playgroud)