代码之家  ›  专栏  ›  技术社区  ›  ControlAltDel

浏览器在什么条件下会重新评估和应用CSS选择器和样式?

  •  1
  • ControlAltDel  · 技术社区  · 4 年前

    严格地说,CSS 3、html 5和样式表或顶级标记中定义的样式:

    这就是我观察到的:

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

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

    我想兄弟姐妹的关系也是如此?我的意思是相对于兄弟姐妹移动元素?

    还有什么会引发这一切吗?在某个地方(比如mozilla)有没有一个文档将其指定为标准?

    0 回复  |  直到 4 年前
        1
  •  2
  •   Kaiido    4 年前

    这取决于你所说的“重新排序”。

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

    对DOM的任何更改都会将CSSOM标记为脏,在渲染之前,如果CSSOM是脏的,浏览器将执行这样的回流。
    请注意,有些操作(大多数在 this gist 保罗·爱尔兰(Paul Irish),将迫使 同步的 回流,因为它们确实需要计算最新的装箱模型,以返回正确的值或正确操作。因此,在循环中进行DOM更改时必须小心,不要强制进行这种同步回流,让浏览器在最佳时间进行(通常是在下一次绘制之前,但在某些浏览器中也是在空闲时进行)。

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

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

    规范中并没有明确规定触发这些操作的原因,甚至没有规定应该在什么时候触发这些操作。HTML规范只要求浏览器执行 "rendering steps" of the event-loop ,它的结尾是一个非常不明确的“ 更新该文档的呈现或用户界面 “。ResizeObserver API将渲染步骤扩展到 include styles recalc and layout update 但他们并没有定义这些步骤。请注意,有一个 open issue 在HTML规范中对其进行了更清晰的定义,但目前我们甚至没有浏览器互操作性。

        2
  •  0
  •   traktor    4 年前

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

    CSS2 definitions 将渲染内容定义为(重点)

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

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

    我的经验是,浏览器在使用JavaScript时会更新DOM 1. 代码在DOM中添加、移动或删除元素,以及在样式表内容或元素发生更改时添加、移动或删除元素 style 属性在脚本中更新。DOM中似乎发生了变化 同步地 修改元素放置或样式规则时:获取DOM中元素的边界矩形(其在DOM中的样式或位置已被修改)不需要浏览 提供 首先是内容。

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

    重新排序

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

    • 如果更改元素在DOM中的位置,则从用于更改其位置的方法返回时,该元素的位置已更改。

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

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

    关于这一点的MDN文章中有一个暗示 `Window.getCommputedStyle .总的来说,我不认为在任何地方特别提到它,因为它是DOM行为中固有的。只有当a)你需要同步使用更改的结果,b)好奇为什么它会像你希望的那样工作时,你才能了解它!:)

    显示同步结果的示例:

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

    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 更广泛的治疗。