浏览器将重新评估并重新应用 CSS 选择器和样式的条件是什么?

What are the conditions under which a browser will re-assess and reapply CSS selectors and styles?

严格谈论 CSS 3、html 5,以及在样式表或顶级标签中定义的样式:

这是我观察到的:

使用JavaScript: 如果我将一个元素移到另一个元素下,或从其父元素下移出,它及其下的所有元素将被审查以重新设计样式。

如果我添加或删除 class,一个元素及其下的所有元素将被审查以重新设计样式。 如果我添加或删除一个属性,一个元素及其下的所有元素将被审查以重新设计样式。

我假设兄弟姐妹 (~) 关系也是如此?我的意思是相对于它们的兄弟姐妹移动元素?

还有什么可以触发这个吗?是否有某处文档(如 mozilla)将其指定为标准?

CSS3 是一系列涵盖各个主题的单独规范,但在 official definition of CSS.

中包含 CSS2

CSS2 definitions 将呈现的内容定义为(强调我的)

The content of an element after the rendering that applies to it according to the relevant style sheets has been applied. How a replaced element's content is rendered is not defined by this specification. Rendered content may also be alternate text for an element (e.g., the value of the XHTML "alt" attribute), and may include items inserted implicitly or explicitly by the style sheet, such as bullets, numbering, etc.

我认为这意味着当呈现文档或其一部分时,浏览器负责确保根据呈现的内容正确应用 CSS 规则,DOM 内容和CSS 规则指定了呈现的逻辑要求,浏览器确保其生成符合逻辑模型的页面布局。

我的经验是浏览器会更新 DOM 当 vanilla JavaScript1 代码添加、移动或删除 DOM 中的元素时,以及在脚本中更新样式 sheet 内容或元素 style 属性的更改时。 DOM 中的更改似乎在修改元素放置或样式规则时 同步发生 :获取 DOM 中元素的边界矩形,其样式或位置在DOM 已修改不需要先浏览 render 内容。

因此,除了措辞之外,您关于可以依赖的内容的基本假设基本上是正确的

reviewed for restyling

没有发生活动的“审查”——除了修改某些属性可以触发自动同步回流操作,以便调用脚本同步访问 DOM 属性 值需要回流计算。

  • 如果您在 DOM 中更改某个元素的位置,它的位置在 return 时已从用于更改其位置的方法更改。

  • 如果您添加、删除或修改元素的属性(在 DOM 中),对属性的更改和产生的任何副作用将在 return 来自用于进行更改的方法。

  • 如果添加、删除或修改样式 sheet 规则,更改在结果中生效 returned from DOM 检查后用于更改的方法样式 sheet returns.

`Window.getCommputedStyle 上的 MDN 文章中对此有所暗示。总的来说,我不认为它在任何地方被特别提及,因为它是 DOM 行为中固有的。只有在 a) 您需要同步使用更改的结果和 b) 好奇为什么它会像您希望的那样工作时,您才会了解它! :)

显示同步结果的示例:

更改 DOM 中的元素位置,style 属性更改:

setTimeout( ()=> {
  const [div1, div2] = Array.from(document.querySelectorAll('div'));
  div2.appendChild(div1);
  div1.style.backgroundColor = "yellow";
  div1.style.textAlign = "center";
  const rect = div1.getBoundingClientRect();
  const style = getComputedStyle(div1);
  console.log("Synchronous results for div1: ",
    {top: rect.top, backgroundColor: style.backgroundColor});
}, 3000);
  
<div>Division 1</div>
<div>Division 2</div>
... please wait 3 seconds

正在更改 CSSOM

中的 CSS 规则

"use strict";
let div = document.querySelector('div');
let sheet = Array.from(document.styleSheets)
  .find(sheet=> sheet.ownerNode.id == "absDiv");

console.log("div offsetWidth ",  div.offsetWidth); // before

sheet.insertRule("div{ width: 200px;}");

console.log("after width set in CSS: ",  div.offsetWidth);
<style id="absDiv">
div { background-color: yellow; }
</style>
<div>Div element</div>


1 Vanilla Javascript 隐式排除影子 DOM 和组件的情况。请参阅 进行更广泛的处理。

这实际上取决于您所说的“重新设计”。

这里好像只是在谈论重新计算文档中所有样式表应用的所有样式,也称为“回流”或“布局”。

对 DOM 的任何更改都会将 CSSOM 标记为脏,并且在渲染之前,如果 CSSOM 是脏的,浏览器将执行这样的重排。
请注意,某些操作(大多数被 Paul Irish 在 this gist 中引用)将强制执行 同步 回流,因为它们确实需要最新的装箱模型计算出 return 正确的值,或正确地行动。因此,在循环中进行 DOM 更改时必须小心,不要强制执行此类同步回流,并让浏览器在最佳时间执行此操作,(通常在下一次绘制之前,但在某些浏览器中也已完成闲置)。

然而,这种回流可能不会花费太多,浏览器可能有足够的优化来知道可能发生了什么变化,并且只通过这些。而且,这些不包括重绘操作,重绘操作只会在下次屏幕刷新时发生。

但这不是浏览器需要重新计算框布局的唯一时间,例如每次调整页面大小时,或者即使流入元素的大小作为动画的一部分发生变化等,但在这里,不会重新计算完整的样式表。

规范中并没有真正定义应该触发这些操作的地方,甚至也没有定义它们应该发生的时间。 HTML规范只是要求浏览器对HTML规范进行"rendering steps" of the event-loop, which does end with a quite underspecified "update the rendering or user interface of that Document". The ResizeObserver API does extend the rendering step to include styles recalc and layout update but they don't go as far as defining these steps. Note that there is an open issue来定义得更清楚,但目前我们连浏览器互操作性都没有。