我想在DOM中动态设置给定选择器的所有元素。我或多或少地看到了两种方式。对于下面的示例,我将使用p
元素及其text-align
属性,但我对这两种可能的方法的优缺点比我特别是文本对齐更感兴趣段落。
var nodes = document.getElementsByTagName('p');
Array.prototype.forEach.call (nodes, function (node) {
node.style.textAlign = "center";
});
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; }");
通常我会选择内联样式的路径,因为它看起来更简单,并确保样式更改将覆盖现有的样式表。但是对于我来说,有一种情况:有时不会覆盖样式表可能更可取,而且对于两个:修改一个style
元素可能比未知数量的p
元素更高效。但这只是我的假设。
性能方面,是否会出现将内联样式应用于每个单独元素比创建样式表更好的情况?假设答案可能取决于我造型的元素数量,那么创建样式表会变得更有效吗?
编辑:为了澄清为什么我会问这个问题,我会解释一下我为什么要问:我最近变成了一些JS黑客,我经常在项目之间复制粘贴和修改一组可重用的CommonJS模块。在最大或最宽的度量可能会在窗口调整大小或其他触发器上发生变化的情况下,它们执行诸如将给定选择器的所有元素设置为与集合中最高或最宽的相同高度或宽度的事情。以下是关于它的博文:http://davejtoews.com/blog/post/javascript-layout-hacks
以下是模块的GitHub存储库:
此时,所有这些模块都使用内联样式,但我正在考虑将它们切换到样式表。我无法找到关于任何一种方法的利弊的好答案,所以我在这里发布了这个问题。
答案 0 :(得分:5)
自从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文件。
答案 1 :(得分:3)
我对你的问题没有一个很好的一般性答案(我不确定是否有),但我已经使用开发工具对您在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>
答案 2 :(得分:2)
这一切都取决于你想要完成的事情的背景。在我目前的雇主,我最终创建了一个名为stylo的小型库,负责更新动态样式表。
当您尝试更新的项目数量为数千时,通过内联样式进行更新将非常昂贵。上面链接中的演示在几分之一秒内更新了6,400项。
但是,如果您只更新少数几个项目,更新样式表可能会触发整个页面重新渲染,如果更新内联样式则不会出现这种情况。