<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      你不知道的 CSS 之包含塊

      你不知道的 CSS 之包含塊

      一說(shuō)到 CSS 盒模型,這是很多小伙伴耳熟能詳?shù)闹R(shí),甚至有的小伙伴還能說(shuō)出 border-box 和 content-box 這兩種盒模型的區(qū)別。

      但是一說(shuō)到 CSS 包含塊,有的小伙伴就懵圈了,什么是包含塊?好像從來(lái)沒(méi)有聽說(shuō)過(guò)這玩意兒。

      image-20220814222004395

      好吧,如果你對(duì)包含塊的知識(shí)一無(wú)所知,那么系好安全帶,咱們準(zhǔn)備出發(fā)了。

      image-20220813140434032

      包含塊英語(yǔ)全稱為containing block,實(shí)際上平時(shí)你在書寫 CSS 時(shí),大多數(shù)情況下你是感受不到它的存在,因此你不知道這個(gè)知識(shí)點(diǎn)也是一件很正常的事情。但是這玩意兒是確確實(shí)實(shí)存在的,在 CSS 規(guī)范中也是明確書寫了的:

      https://drafts.csswg.org/css2/#containing-block-details

      image-20220814222458695

      并且,如果你不了解它的運(yùn)作機(jī)制,有時(shí)就會(huì)出現(xiàn)一些你認(rèn)為的莫名其妙的現(xiàn)象。

      那么,這個(gè)包含塊究竟說(shuō)了什么內(nèi)容呢?

      說(shuō)起來(lái)也簡(jiǎn)單,就是元素的尺寸和位置,會(huì)受它的包含塊所影響。對(duì)于一些屬性,例如 width, height, padding, margin,絕對(duì)定位元素的偏移值(比如 position 被設(shè)置為 absolute 或 fixed),當(dāng)我們對(duì)其賦予百分比值時(shí),這些值的計(jì)算值,就是通過(guò)元素的包含塊計(jì)算得來(lái)。

      來(lái)吧,少年,讓我們從最簡(jiǎn)單的 case 開始看。

      image-20220814223152726
      <body>
        <div class="container">
          <div class="item"></div>
        </div>
      </body>
      
      .container{
        width: 500px;
        height: 300px;
        background-color: skyblue;
      }
      .item{
        width: 50%;
        height: 50%;
        background-color: red;
      }
      

      請(qǐng)仔細(xì)閱讀上面的代碼,然后你認(rèn)為 div.item 這個(gè)盒子的寬高是多少?

      image-20220814223451349

      相信你能夠很自信的回答這個(gè)簡(jiǎn)單的問(wèn)題,div.item 盒子的 width 為 250px,height 為 150px。

      這個(gè)答案確實(shí)是沒(méi)有問(wèn)題的,但是如果我追問(wèn)你是怎么得到這個(gè)答案的,我猜不了解包含塊的你大概率會(huì)說(shuō),因?yàn)樗母冈?div.container 的 width 為 500px,50% 就是 250px,height 為 300px,因此 50% 就是 150px。

      這個(gè)答案實(shí)際上是不準(zhǔn)確的。正確的答案應(yīng)該是,div.item 的寬高是根據(jù)它的包含塊來(lái)計(jì)算的,而這里包含塊的大小,正是這個(gè)元素最近的祖先塊元素的內(nèi)容區(qū)。

      因此正如我前面所說(shuō),很多時(shí)候你都感受不到包含塊的存在。

      包含塊分為兩種,一種是根元素(HTML 元素)所在的包含塊,被稱之為初始包含塊(initial containing block)。對(duì)于瀏覽器而言,初始包含塊的的大小等于視口 viewport 的大小,基點(diǎn)在畫布的原點(diǎn)(視口左上角)。它是作為元素絕對(duì)定位和固定定位的參照物。

      另外一種是對(duì)于非根元素,對(duì)于非根元素的包含塊判定就有幾種不同的情況了。大致可以分為如下幾種:

      • 如果元素的 positiion 是 relative 或 static ,那么包含塊由離它最近的塊容器(block container)的內(nèi)容區(qū)域(content area)的邊緣建立。
      • 如果 position 屬性是 fixed,那么包含塊由視口建立。
      • 如果元素使用了 absolute 定位,則包含塊由它的最近的 position 的值不是 static (也就是值為fixed、absolute、relative 或 sticky)的祖先元素的內(nèi)邊距區(qū)的邊緣組成。

      前面兩條實(shí)際上都還比較好理解,第三條往往是初學(xué)者容易比較忽視的,我們來(lái)看一個(gè)示例:

      <body>
          <div class="container">
            <div class="item">
              <div class="item2"></div>
            </div>
          </div>
        </body>
      
      .container {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        position: relative;
      }
      .item {
        width: 300px;
        height: 150px;
        border: 5px solid;
        margin-left: 100px;
      }
      .item2 {
        width: 100px;
        height: 100px;
        background-color: red;
        position: absolute;
        left: 10px;
        top: 10px;
      }
      

      首先閱讀上面的代碼,然后你能在腦海里面想出其大致的樣子么?或者用筆和紙畫一下也行。

      公布正確答案:

      image-20220814233548188

      怎么樣?有沒(méi)有和你所想象的對(duì)上?

      其實(shí)原因也非常簡(jiǎn)單,根據(jù)上面的第三條規(guī)則,對(duì)于 div.item2 來(lái)講,它的包含塊應(yīng)該是 div.container,而非 div.item。

      如果你能把上面非根元素的包含塊判定規(guī)則掌握,那么關(guān)于包含塊的知識(shí)你就已經(jīng)掌握 80% 了。

      實(shí)際上對(duì)于非根元素來(lái)講,包含塊還有一種可能,那就是如果 position 屬性是 absolute 或 fixed,包含塊也可能是由滿足以下條件的最近父級(jí)元素的內(nèi)邊距區(qū)的邊緣組成的:

      • transform 或 perspective 的值不是 none
      • will-change 的值是 transform 或 perspective
      • filter 的值不是 none 或 will-change 的值是 filter(只在 Firefox 下生效).
      • contain 的值是 paint (例如: contain: paint;)

      我們還是來(lái)看一個(gè)示例:

      <body>
        <div class="container">
          <div class="item">
            <div class="item2"></div>
          </div>
        </div>
      </body>
      
      .container {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        position: relative;
      }
      .item {
        width: 300px;
        height: 150px;
        border: 5px solid;
        margin-left: 100px;
        transform: rotate(0deg); /* 新增代碼 */
      }
      .item2 {
        width: 100px;
        height: 100px;
        background-color: red;
        position: absolute;
        left: 10px;
        top: 10px;
      }
      

      我們對(duì)于上面的代碼只新增了一條聲明,那就是 transform: rotate(0deg),此時(shí)的渲染效果卻發(fā)生了改變,如下圖所示:

      image-20220814234347149

      可以看到,此時(shí)對(duì)于 div.item2 來(lái)講,包含塊就變成了 div.item。

      好了,到這里,關(guān)于包含塊的知識(shí)就基本講完了。

      image-20220814234654914

      我們?cè)侔?CSS 規(guī)范中所舉的例子來(lái)看一下。

      <html>
        <head>
          <title>Illustration of containing blocks</title>
        </head>
        <body id="body">
          <div id="div1">
            <p id="p1">This is text in the first paragraph...</p>
            <p id="p2">
              This is text
              <em id="em1">
                in the
                <strong id="strong1">second</strong>
                paragraph.
              </em>
            </p>
          </div>
        </body>
      </html>
      

      上面是一段簡(jiǎn)單的 HTML 代碼,在沒(méi)有添加任何 CSS 代碼的情況下,你能說(shuō)出各自的包含塊么?

      對(duì)應(yīng)的結(jié)果如下:

      元素 包含塊
      html initial C.B. (UA-dependent)
      body html
      div1 body
      p1 div1
      p2 div1
      em1 p2
      strong1 p2

      首先 HTML 作為根元素,對(duì)應(yīng)的包含塊就是前面我們所說(shuō)的初始包含塊,而對(duì)于 body 而言,這是一個(gè) static 定位的元素,因此該元素的包含塊參照第一條為 html,以此類推 div1、p1、p2 以及 em1 的包含塊也都是它們的父元素。

      不過(guò) strong1 比較例外,它的包含塊確實(shí) p2,而非 em1。為什么會(huì)這樣?建議你再把非根元素的第一條規(guī)則讀一下:

      • 如果元素的 positiion 是 relative 或 static ,那么包含塊由離它最近的塊容器(block container)的內(nèi)容區(qū)域(content area)的邊緣建立。

      沒(méi)錯(cuò),因?yàn)?em1 不是塊容器,而包含塊是離它最近的塊容器的內(nèi)容區(qū)域,所以是 p2。

      接下來(lái)添加如下的 CSS:

      #div1 { 
        position: absolute; 
        left: 50px; top: 50px 
      }
      

      上面的代碼我們對(duì) div1 進(jìn)行了定位,那么此時(shí)的包含塊會(huì)發(fā)生變化么?你可以先在自己思考一下。

      答案如下:

      元素 包含塊
      html initial C.B. (UA-dependent)
      body html
      div1 initial C.B. (UA-dependent)
      p1 div1
      p2 div1
      em1 p2
      strong1 p2

      可以看到,這里 div1 的包含塊就發(fā)生了變化,變?yōu)榱顺跏及瑝K。這里你可以參考前文中的這兩句話:

      • 初始包含塊(initial containing block)。對(duì)于瀏覽器而言,初始包含塊的的大小等于視口 viewport 的大小,基點(diǎn)在畫布的原點(diǎn)(視口左上角)。它是作為元素絕對(duì)定位和固定定位的參照物。
      • 如果元素使用了 absolute 定位,則包含塊由它的最近的 position 的值不是 static (也就是值為fixed、absolute、relative 或 sticky)的祖先元素的內(nèi)邊距區(qū)的邊緣組成。

      是不是一下子就理解了。沒(méi)錯(cuò),因?yàn)槲覀儗?duì) div1 進(jìn)行了定位,因此它會(huì)應(yīng)用非根元素包含塊計(jì)算規(guī)則的第三條規(guī)則,尋找離它最近的 position 的值不是 static 的祖先元素,不過(guò)顯然 body 的定位方式為 static,因此 div1 的包含塊最終就變成了初始包含塊。

      接下來(lái)我們繼續(xù)修改我們的 CSS:

      #div1 { 
        position: absolute; 
        left: 50px; 
        top: 50px 
      }
      #em1  { 
        position: absolute; 
        left: 100px; 
        top: 100px 
      }
      

      這里我們對(duì) em1 同樣進(jìn)行了 absolute 絕對(duì)定位,你想一想會(huì)有什么樣的變化?

      沒(méi)錯(cuò),聰明的你大概應(yīng)該知道,em1 的包含塊不再是 p2,而變成了 div1,而 strong1 的包含塊也不再是 p2 了,而是變成了 em1。

      如下表所示:

      元素 包含塊
      html initial C.B. (UA-dependent)
      body html
      div1 initial C.B. (UA-dependent)
      p1 div1
      p2 div1
      em1 div1(因?yàn)槎ㄎ涣耍瑓㈤喎歉匕瑝K確定規(guī)則的第三條)
      strong1 em1(因?yàn)?em1 變?yōu)榱藟K容器,參閱非根元素包含塊確定規(guī)則的第一條)

      好了,這就是 CSS 規(guī)范中所舉的例子。如果你全都能看明白,以后你還能跟別人說(shuō)你是看過(guò)這一塊知識(shí)對(duì)應(yīng)的 CSS 規(guī)范的人。

      image-20220815093518833

      另外,關(guān)于包含塊的知識(shí),在 MDN 上除了解說(shuō)了什么是包含塊以外,也舉出了很多簡(jiǎn)單易懂的示例。

      具體你可以移步到:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Containing_block

      好了,這就是有關(guān)包含塊的所有內(nèi)容了,你學(xué)會(huì)了么?-)


      附加

      面試題

      瀏覽器是如何渲染頁(yè)面的?

      當(dāng)瀏覽器的網(wǎng)絡(luò)線程收到 HTML 文檔后,會(huì)產(chǎn)生一個(gè)渲染任務(wù),并將其傳遞給渲染主線程的消息隊(duì)列。

      在事件循環(huán)機(jī)制的作用下,渲染主線程取出消息隊(duì)列中的渲染任務(wù),開啟渲染流程。


      整個(gè)渲染流程分為多個(gè)階段,分別是: HTML 解析、樣式計(jì)算、布局、分層、繪制、分塊、光柵化、畫

      每個(gè)階段都有明確的輸入輸出,上一個(gè)階段的輸出會(huì)成為下一個(gè)階段的輸入。

      這樣,整個(gè)渲染流程就形成了一套組織嚴(yán)密的生產(chǎn)流水線。


      渲染的第一步是解析 HTML

      解析過(guò)程中遇到 CSS 解析 CSS,遇到 JS 執(zhí)行 JS。為了提高解析效率,瀏覽器在開始解析前,會(huì)啟動(dòng)一個(gè)預(yù)解析的線程,率先下載 HTML 中的外部 CSS 文件和 外部的 JS 文件。

      如果主線程解析到link位置,此時(shí)外部的 CSS 文件還沒(méi)有下載解析好,主線程不會(huì)等待,繼續(xù)解析后續(xù)的 HTML。這是因?yàn)橄螺d和解析 CSS 的工作是在預(yù)解析線程中進(jìn)行的。這就是 CSS 不會(huì)阻塞 HTML 解析的根本原因。

      如果主線程解析到script位置,會(huì)停止解析 HTML,轉(zhuǎn)而等待 JS 文件下載好,并將全局代碼解析執(zhí)行完成后,才能繼續(xù)解析 HTML。這是因?yàn)?JS 代碼的執(zhí)行過(guò)程可能會(huì)修改當(dāng)前的 DOM 樹,所以 DOM 樹的生成必須暫停。這就是 JS 會(huì)阻塞 HTML 解析的根本原因。

      第一步完成后,會(huì)得到 DOM 樹和 CSSOM 樹,瀏覽器的默認(rèn)樣式、內(nèi)部樣式、外部樣式、行內(nèi)樣式均會(huì)包含在 CSSOM 樹中。


      渲染的下一步是樣式計(jì)算

      主線程會(huì)遍歷得到的 DOM 樹,依次為樹中的每個(gè)節(jié)點(diǎn)計(jì)算出它最終的樣式,稱之為 Computed Style。

      在這一過(guò)程中,很多預(yù)設(shè)值會(huì)變成絕對(duì)值,比如red會(huì)變成rgb(255,0,0);相對(duì)單位會(huì)變成絕對(duì)單位,比如em會(huì)變成px

      這一步完成后,會(huì)得到一棵帶有樣式的 DOM 樹。


      接下來(lái)是布局,布局完成后會(huì)得到布局樹。

      布局階段會(huì)依次遍歷 DOM 樹的每一個(gè)節(jié)點(diǎn),計(jì)算每個(gè)節(jié)點(diǎn)的幾何信息。例如節(jié)點(diǎn)的寬高、相對(duì)包含塊的位置。

      大部分時(shí)候,DOM 樹和布局樹并非一一對(duì)應(yīng)。

      比如display:none的節(jié)點(diǎn)沒(méi)有幾何信息,因此不會(huì)生成到布局樹;又比如使用了偽元素選擇器,雖然 DOM 樹中不存在這些偽元素節(jié)點(diǎn),但它們擁有幾何信息,所以會(huì)生成到布局樹中。還有匿名行盒、匿名塊盒等等都會(huì)導(dǎo)致 DOM 樹和布局樹無(wú)法一一對(duì)應(yīng)。


      下一步是分層

      主線程會(huì)使用一套復(fù)雜的策略對(duì)整個(gè)布局樹中進(jìn)行分層。

      分層的好處在于,將來(lái)某一個(gè)層改變后,僅會(huì)對(duì)該層進(jìn)行后續(xù)處理,從而提升效率。

      滾動(dòng)條、堆疊上下文、transform、opacity 等樣式都會(huì)或多或少的影響分層結(jié)果,也可以通過(guò)will-change屬性更大程度的影響分層結(jié)果。


      再下一步是繪制

      主線程會(huì)為每個(gè)層單獨(dú)產(chǎn)生繪制指令集,用于描述這一層的內(nèi)容該如何畫出來(lái)。


      完成繪制后,主線程將每個(gè)圖層的繪制信息提交給合成線程,剩余工作將由合成線程完成。

      合成線程首先對(duì)每個(gè)圖層進(jìn)行分塊,將其劃分為更多的小區(qū)域。

      它會(huì)從線程池中拿取多個(gè)線程來(lái)完成分塊工作。


      分塊完成后,進(jìn)入光柵化階段。

      合成線程會(huì)將塊信息交給 GPU 進(jìn)程,以極高的速度完成光柵化。

      GPU 進(jìn)程會(huì)開啟多個(gè)線程來(lái)完成光柵化,并且優(yōu)先處理靠近視口區(qū)域的塊。

      光柵化的結(jié)果,就是一塊一塊的位圖


      最后一個(gè)階段就是

      合成線程拿到每個(gè)層、每個(gè)塊的位圖后,生成一個(gè)個(gè)「指引(quad)」信息。

      指引會(huì)標(biāo)識(shí)出每個(gè)位圖應(yīng)該畫到屏幕的哪個(gè)位置,以及會(huì)考慮到旋轉(zhuǎn)、縮放等變形。

      變形發(fā)生在合成線程,與渲染主線程無(wú)關(guān),這就是transform效率高的本質(zhì)原因。

      合成線程會(huì)把 quad 提交給 GPU 進(jìn)程,由 GPU 進(jìn)程產(chǎn)生系統(tǒng)調(diào)用,提交給 GPU 硬件,完成最終的屏幕成像。

      什么是 reflow?

      reflow 的本質(zhì)就是重新計(jì)算 layout 樹。

      當(dāng)進(jìn)行了會(huì)影響布局樹的操作后,需要重新計(jì)算布局樹,會(huì)引發(fā) layout。

      為了避免連續(xù)的多次操作導(dǎo)致布局樹反復(fù)計(jì)算,瀏覽器會(huì)合并這些操作,當(dāng) JS 代碼全部完成后再進(jìn)行統(tǒng)一計(jì)算。所以,改動(dòng)屬性造成的 reflow 是異步完成的。

      也同樣因?yàn)槿绱耍?dāng) JS 獲取布局屬性時(shí),就可能造成無(wú)法獲取到最新的布局信息。

      瀏覽器在反復(fù)權(quán)衡下,最終決定獲取屬性立即 reflow。

      什么是 repaint?

      repaint 的本質(zhì)就是重新根據(jù)分層信息計(jì)算了繪制指令。

      當(dāng)改動(dòng)了可見樣式后,就需要重新計(jì)算,會(huì)引發(fā) repaint。

      由于元素的布局信息也屬于可見樣式,所以 reflow 一定會(huì)引起 repaint。

      為什么 transform 的效率高?

      因?yàn)?transform 既不會(huì)影響布局也不會(huì)影響繪制指令,它影響的只是渲染流程的最后一個(gè)「draw」階段

      由于 draw 階段在合成線程中,所以 transform 的變化幾乎不會(huì)影響渲染主線程。反之,渲染主線程無(wú)論如何忙碌,也不會(huì)影響 transform 的變化。


      -EOF-

      posted @ 2024-06-20 23:02  二價(jià)亞鐵  閱讀(424)  評(píng)論(1)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产亚洲精品综合99久久| 激情综合网激情五月伊人| 人妻无码不卡中文字幕系列| 国内自产少妇自拍区免费| 日韩伦人妻无码| 精品国产女同疯狂摩擦2 | 久久精品国产亚洲av麻豆长发| 妖精视频亚州无吗高清版| 国产av午夜精品福利| 国产中文三级全黄| 日本一区二区三区四区黄色| 欧洲亚洲国内老熟女超碰| 四虎成人高清永久免费看| 四虎影视一区二区精品| 在线精品自拍亚洲第一区| 国产伦精品一区二区三区免费迷| 久久综合老鸭窝色综合久久| 国产片AV国语在线观看手机版| 亚洲日韩精品无码一区二区三区| 中文无码热在线视频| 亚洲欧美人成电影在线观看| av中文字幕一区人妻| 人人妻人人澡人人爽人人精品av| 国产熟女50岁一区二区| 在线中文字幕国产精品| 日韩人妻无码一区二区三区99| 又大又紧又粉嫩18p少妇| 欧美中文字幕在线看| 亚洲av永久无码精品网站| 国产成人av免费网址| 久久99日本免费国产精品| www久久只有这里有精品| 40岁大乳的熟妇在线观看| 久久综合色最新久久综合色| 欧美日韩v| 人妻av中文字幕无码专区| 郸城县| 国产精品成人午夜久久| 精品熟女日韩中文十区| 又长又粗又爽又高潮的视频| 粉嫩一区二区三区国产精品 |