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

Posted

技术标签:

【中文标题】浏览器重新评估和重新应用 CSS 选择器和样式的条件是啥?【英文标题】:What are the conditions under which a browser will re-assess and reapply CSS selectors and styles?浏览器重新评估和重新应用 CSS 选择器和样式的条件是什么? 【发布时间】:2022-01-20 18:32:46 【问题描述】:

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

这是我观察到的:

使用 javascript: 如果我将一个元素移到另一个元素下,或者从它的父元素下移出,它和它下面的所有元素都将被重新设计。

如果我添加或删除一个类,一个元素及其下的所有元素都将被重新设计。 如果我添加或删除一个属性,一个元素及其下的所有元素都将被重新设计。

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

还有什么会触发这个吗?是否有某个地方(如 mozilla)将其指定为标准?

【问题讨论】:

也许这会有所帮助:developer.mozilla.org/en-US/docs/Learn/CSS/First_steps/… 这是一个很好的资源:@​​987654322@ - 我将您放在文档中间,以便了解您的问题。阅读该部分,然后阅读其余部分。最后有一个参考书目,供各种技术参考。 【参考方案1】:

CSS3 是一系列单独的规范,涵盖各个主题,但在 official definition of CSS 中包含 CSS2。

CSS2 definitions 将渲染内容定义为(强调我的)

根据相关样式表应用于元素的渲染后的元素内容已被应用。 本规范未定义替换元素的内容如何呈现。呈现的内容也可以是元素的替代文本(例如,XHTML“alt”属性的值),并且可能包括由样式表隐式或显式插入的项目,例如项目符号、编号等。

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

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

因此,除了措辞之外,您对可以依赖的东西的基本假设基本上是正确的

经过重新设计审核

没有进行活动的“审查” - 除了修改某些属性可以触发自动和同步的重排操作,以便调用脚本能够同步访问需要重排来计算的 DOM 属性值。

如果你改变了一个元素在 DOM 中的位置,它的位置在从用于改变它的位置的方法返回时已经改变了。

如果您添加、删除或修改元素的属性(在 DOM 中),对属性的更改和产生的任何副作用都将在从用于进行更改的方法返回时生效。

如果您添加、删除或修改样式表规则,更改在用于更改样式表的方法返回后对DOM检查返回的结果有效。

在 `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 和组件的情况。请参阅Kaido's answer 以获得更广泛的治疗。

【讨论】:

【参考方案2】:

这真的取决于你所说的“重新设计”。

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

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

然而,这种重排可能不会花费太多,但浏览器很可能有足够的优化来了解可能发生的变化并仅通过这些优化。此外,这些不包括仅在下次屏幕刷新时发生的重绘操作。

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

规范中并没有真正定义什么应该触发这些操作,甚至没有定义它们应该何时发生。 HTML 规范只要求浏览器执行"rendering steps" of the event-loop,它确实以完全未指定的“更新该文档的呈现或用户界面”结束。 ResizeObserver API 确实将渲染步骤扩展到include styles recalc and layout update,但它们并没有定义这些步骤。请注意,HTML 规范中有一个open issue 可以更清楚地定义它,但目前我们甚至没有浏览器互操作性。

【讨论】:

您是否有证据表明 CSSOM 被标记为脏?我会认为 CSSOM 是独立于 DOM 的(除非样式表本身被更改),因此标记为脏的是框树,而不是 CSSOM。 @Alohci 我认为盒子树是 CSSOM 的一部分,以及计算值等。

以上是关于浏览器重新评估和重新应用 CSS 选择器和样式的条件是啥?的主要内容,如果未能解决你的问题,请参考以下文章

CSS选择器详解通用选择器和高级选择器

为啥在重新计算 chrome 开发工具中的样式之前评估过 js?

React项目的css样式,为啥标签选择器和ID选择器可以生效,类选择器不行呢?

销毁或重新计算 CSS nth-child 选择器

CSS样式表和元素选择器

CSS 用法和特性