css溢出機制探究

爲何須要深刻學習CSS溢出機制?

在實際開發的過程當中,內容溢出是常常見到的。若是不深刻了解這個機制,你常常會碰到這樣的問題:爲何這個元素沒有受到祖先元素的overflow:hidden的影響?這裏出現的滾動條是哪一個元素的?如何消除這個滾動條?如何在指定的元素上增長滾動功能?
在這篇文章,咱們將會從CSS標準出發,討論CSS溢出機制的細節。css

溢出

當一個盒子(block container box)的內容(子元素、孫子元素等後裔)超過盒子自己的大小的時候,就會出現溢出。這個時候CSS屬性overflow決定如何處理溢出。這個css屬性你們都知道,在這裏不討論了,在這裏指出須要注意的幾點:html

  • overflow會影響所在元素的全部內容的裁剪、滾動,可是有一種狀況例外:"It affects the clipping of all of the element's content except any descendant elements (and their respective content and descendants) whose containing block is the viewport or an ancestor of the element." 也就是說,overflow的所在元素必須是內容元素的直接或間接containing block,這時overflow屬性纔會影響這個內容元素。好比<A><B><C><C/><B/><A/>,通常來講,B的overflow會影響C,可是若是C是相對於viewport或者A定位的(好比使用了position:absolute),那麼C的顯示就不受B的裁剪、滾動的影響。
  • 當須要滾動條的時候,滾動條會放在border與padding之間。父元素產生滾動條之後,它產生的containing block的尺寸會減小,以便給滾動條騰出空間。
  • CSS3文檔:"When the viewport is smaller than the area of the canvas on which the document is rendered, the user agent may offer a scrolling mechanism." 即,visual viewport能夠擁有滾動條。
  • 在<html>和<body>上的overflow屬性存在冒泡現象: "UAs must apply the 'overflow' property set on the root element to the viewport. When the root element is an HTML "HTML" element or an XHTML "html" element, and that element has an HTML "BODY" element or an XHTML "body" element as a child, user agents must instead apply the 'overflow' property from the first such child element to the viewport, if the value on the root element is 'visible'. The 'visible' value when used for the viewport must be interpreted as 'auto'. The element from which the value is propagated must have a used value for 'overflow' of 'visible'. "
    意思是:viewport的overflow屬性是從<html>或者<body>元素竊取來的:若是<html>的overflow不是'visible'(默認值),那就從<html>竊取;不然,從<body>竊取。若是viewport竊取來的overflow是'visible',那麼將它視爲'auto'(由於不可能在viewport以外顯示內容)。被竊取的元素,它的overflow被設置爲'visible'。

能夠推斷出:chrome

  • 通常來講只有元素才能擁有滾動條(更準確地說,只有產生block container box元素才能擁有滾動條)。但visual viewport是個例外。它雖然不是一個元素,可是也能夠擁有滾動條。若是在<html>和<body>上都沒有設置overflow屬性而使用默認值visible(大部分場景都是這樣),那麼,visual viewport的overflow就是auto:當網頁中有內容超出visual viewport時,visual viewport上會出現滾動條。canvas

    關於viewport的討論在 【響應式佈局】initial containing block、viewport以及相關尺寸
  • <html>的最終overflow永遠都是visible。也就是說,<html>元素永遠不可能擁有滾動條。
  • 若是你想要爲<body>設置非visible的overflow,須要先爲<html>設置一個非visible的值來冒泡,從而<body>的overflow不會被冒泡。

小練習

小練習:利用以上原理,使visual viewport和<body>都擁有橫、豎滾動條,總共4個滾動條。不能使用overflow: scroll(這樣就太簡單了)。
步驟:segmentfault

  1. 使visual viewport和<body>的最終overflow值都爲auto,從而能夠出現滾動條。
  2. 觸發visual viewport和<body>的溢出。經過【爲內容設置一個更大的尺寸】來作到。

代碼+註釋:瀏覽器

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <title>test</title>
  <style>
    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
    }

    html {
      /* 使html的尺寸始終與visual viewport相同(即便你縮放、調整瀏覽器窗口的大小),從而body能夠設置一個比visual viewport還大的尺寸(110%)。
      對於默認爲block的元素能夠省略width: 100%; */
      width: 100%;
      height: 100%;
      /* 非visible的值冒泡到visual viewport上,使visual viewport能夠出現滾動條 */
      overflow: auto;
      border: 15px solid red;
    }

    body {
      /* 使得body能夠出現滾動條 */
      overflow: auto;
      /* body溢出html,從而溢出initial containning block,從而溢出visual viewport,使得visual viewport出現滾動條。
      固然,你也能夠經過不少其餘的方式來觸發visual viewport的溢出,好比增大html元素,或者在body中弄一個position: absolute的div */
      width: 110%;
      height: 110%;
      border: 15px solid green;
    }

    main {
      /* main溢出body,使得body出現滾動條 */
      width: 110%;
      height: 110%;
      border: 15px solid blue;
    }
  </style>
</head>

<body>
  <main>
  </main>
</body>

</html>

結果:
app

本身在chrome中打開以上代碼,能更加清晰地看出是怎麼作到的。

也能夠經過absolute的方式來溢出initial containing block:佈局

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <title>test</title>
  <style>
    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
    }

    html {
      /* 使html的尺寸始終與visual viewport相同(即便你縮放、調整瀏覽器窗口的大小),從而body能夠設置一個比visual viewport還大的尺寸(110%)。
      對於默認爲block的元素能夠省略width: 100%; */
      width: 100%;
      height: 100%;
      /* 非visible的值冒泡到visual viewport上,使visual viewport能夠出現滾動條 */
      overflow: auto;
      border: 15px solid red;
    }

    body {
      /* 使得body能夠出現滾動條 */
      overflow: auto;
      /* 爲body設置一個尺寸,從而main能夠設置一個比body還大的尺寸(110%)。
      對於默認爲block的元素能夠省略width: 100%; */
      height: 100%;
      border: 15px solid green;
    }

    main {
      /* main溢出body,使得body出現滾動條 */
      width: 110%;
      height: 110%;
      border: 15px solid blue;
    }

    .abs {
      /* 經過absolute的方式來溢出initial containing block,從而溢出viewport */
      position: absolute;
      width: 100px;
      height: 100px;
      right: -100px;
      bottom: -100px;
      border: 15px solid blueviolet;
    }
  </style>
</head>

<body>
  <main>
  </main>

  <div class="abs"></div>
</body>

</html>

結果:
學習

本身在chrome中打開以上代碼,能更加清晰地看出是怎麼作到的。

如何看出某個滾動條是屬於哪一個元素的?

經過Chrome DevTools就能夠看出滾動條的所屬元素。
前面已經說過,滾動條的位置在元素的border與padding之間。當你使用Chrome DevTools選中某個元素,發現滾動條剛好在高亮區域(border)內部時,滾動條就屬於當前元素。
spa

要判斷滾動條是否屬於visual viewport,首先先將右邊、下邊的滾動條分別滾動到最下、最右(這一步很重要,它保證沒有內容藏在滾動條下面)。而後,Ctrl+Shift+C選擇右邊或下邊的滾動條,若是高亮的區域不包含這個滾動條,就說明這個滾動條不屬於任何元素,也就是屬於visual viewport。

JavaScript獲取滾動距離

https://developer.mozilla.org...
https://developer.mozilla.org...
獲取或設置元素的內容被滾動的距離。這兩個屬性適用於全部Element。

若是想要獲取visual viewport的滾動距離,除了這個方法之外,還有更多等效的方法。見【響應式佈局】initial containing block、viewport以及相關尺寸

參考資料

  1. css2.1標準
相關文章
相關標籤/搜索