为什么使用 CSS insertRule 时 DOM 不更新?

Why DOM is not updated when using CSS insertRule?

提问人:jcubic 提问时间:11/6/2023 最后编辑:jcubic 更新时间:11/6/2023 访问量:74

问:

我想向 DOM 添加一个 CSS 规则:

这是我的代码

function empty_rule(sheet, class_name) {
    const index = sheet.cssRules.length;
    sheet.insertRule(`.${class_name} { }`, index);
    return sheet.cssRules[index];
}

function make_style() {
  const $head = $('head');
  const $style = $('<style type="text/css"/>').appendTo($head);
  return $style.get(0).sheet;
}

function set_css(sheet, class_name, style) {
    const selector = `.${class_name}`;
    let rule = [...sheet.cssRules].find(rule => {
        return rule.selectorText === selector;
    });
    if (!rule) {
        rule = empty_rule(sheet, class_name);
    }
    Object.assign(rule.style, style);
}


const sheet = make_style();
const rule = empty_rule(sheet, 'cmd-terminal');

console.log(sheet);
console.log(rule);

/*
set_css(sheet, 'cmd-terminal', {
    color: 'red'
});
*/

在 CodePen 上,我添加了这个 CSS 来查看 CSS:

style {
    display: block;
    white-space: pre;
    font-family: monospace;
}

但是我没有看到添加任何CSS,我尝试在评论中添加给定的CSS。但我什至没有看到空的规则。我在问 chatGPT,但它对解决问题没有任何帮助。

这是 CodePen 链接

我使用现金库(轻量级 jQuery 替代方案)。

我试图添加到空规则中(这是 chatGPT 的建议),但它并没有解决问题。display: block;

我什至尝试了 MDN 中的内容:

$('body style').get(0).sheet.insertRule("#blanc { color: white }", 0);

但风格没有改变。

编辑:我添加了:

这个 HTML:

<p id="blanc">hello</p>

我在 Firefox、Google Chrome 和 Safari 中也有相同的行为。

当 JavaScript 运行时,标签会消失。那么问题来了,为什么DOM(devTools)中没有更新样式,为什么我添加的样式没有出现(添加时)?display: block

是否可以更新 DOM,以便您可以更轻松地调试 CSS?

javascript css dom

评论


答:

0赞 jcubic 11/6/2023 #1

因此,cssRules 似乎在 DOM 中不可见。但是您可以创建调试代码来转储 CSS 并将其添加回 DOM:

function dump_css(sheet) {
    return [...sheet.cssRules].map(rule => rule.cssText).join('\n')
}

$('head style:last-child').text(dump_css(sheet));

这会将动态 CSS 呈现到 DOM 中。此代码可以在调试时使用。

请参阅原始 CodePen 演示的这个分支

0赞 myf 11/6/2023 #2

您似乎期望修改“virtual”将反映回 HTMLStyleElement 的“”。但显然,它不会:sheet.CSSRulesinnerHTML

<style
 id=s
 contenteditable
 style="
  display: block;
  white-space: pre;
  border: inset;
">body {
 background-color: darkslategray;
 color: tan;
}

[onclick]:empty::after { content: attr(onclick); }
</style>
i:
<input id=i value="body { color: red; }">
<button onclick="
s.sheet.insertRule(i.value, s.sheet.rules.length);
"></button>

这表明,在不更改原始元素内容的情况下,将新规则添加到附加到样式元素的工作表中具有效力。

评论

0赞 jcubic 11/6/2023
是的,我已经找到了。请参阅末尾的编辑和问题。
-1赞 Usama Sadiq 11/6/2023 #3

在网页中,文档对象模型 (DOM) 不会立即更新,以反映通过使用 insertRule 方法添加新的 CSS 规则对样式表所做的更改。这通常会让开发人员感到困惑,他们认为使用 insertRule 添加新的 CSS 规则会立即更改页面的样式。

这是因为 CSS 对象模型 (CSSOM) 提供了 insertRule 方法,该方法的功能级别低于 DOM。它不会导致页面自动重排或重绘;相反,它允许您以编程方式将新的 CSS 规则添加到样式表中。换句话说,它可以防止浏览器立即重新计算样式并更新呈现的输出。

通常,您必须强制重排或重绘页面,以观察新插入的 CSS 规则的后果。可以更改 DOM 元素的类名,可以更新其内联样式,也可以强制更改布局。下面是如何将最近添加的 CSS 规则应用于特定 JavaScript 元素的示例:

// Create a new CSS rule
var stylesheet = document.styleSheets[0]; // Assuming the stylesheet you want to modify is the first one
var rule = "p { color: red; }";
stylesheet.insertRule(rule, 0); // Insert the rule at the beginning of the stylesheet

// Apply the new CSS rule to a specific element
var paragraph = document.querySelector("p"); // Select the desired paragraph element
paragraph.style.color = "red"; // Update its inline style to trigger the change

在此示例中,我们编辑特定 p 元素的内联样式以立即应用新样式,并包含新的 CSS 规则以将所有 p 元素的文本颜色更改为红色。

虽然 insertRule 支持动态样式表编辑,但它可能只支持有限数量的旧浏览器。因此,您在使用它时应谨慎行事,以防止意外行为。为了更新 DOM 和动态更改样式,类和 JavaScript 的使用频率更高。

评论

3赞 jcubic 11/7/2023
如果代码不是完整的示例,请不要使用堆栈代码段。否则,运行它时将出现错误。此外,这看起来像是用 chatGPT 生成的,这在 StackOverflow 上是不允许的。