CSS進階——絕對定位元素的寬高是如何定義的

無名小貝勒發表於2017-06-05

先拋兩個小問題:

  • 絕對定位相對於誰來定位?
    大多數人都知道是相對於最近的position設定為relative/absolute/fixed的父元素來定位。那如果所有父元素的position都沒有設定上面三個值,那又是相對誰來定位呢?
  • 包含塊是什麼?初始包含塊又是什麼?
    元素A包含元素B,A設定position:relative,B設定position:absolute;left:0;top:0,這個left:0;top:0是相對於A元素的content-box、padding-box還是margin-box的左上角?

如果你還不是很有把握說出來答案,可以先思考一下或者實踐一下,然後再閱讀後面的內容。

絕對定位元素的特性

  • 絕對定位元素完全脫離文件流,不會對後面兄弟元素的佈局產生任何影響
  • 其位置(或者說大小)是由top right bottom left四個屬性決定的
  • 絕對定位元素的margin不會和其他元素的margin摺疊

上面說到絕對定位元素的大小是由top right bottom left四個屬性決定的,這四個屬性是相對於絕對定位元素的包含塊來定位的

包含塊

  • 絕對定位元素的包含塊是由其最近的position屬性設定為relativeabsolutefixed的祖先元素,按照以下方式生成的:

    • 如果這個祖先元素是行內元素...此種情況請參考後續文章
    • 否則,包含塊是由祖先元素的padding edge組成(即相對於祖先元素padding-box進行定位)
  • 如果絕對定位元素的所有祖先元素的position屬性都沒有設定relativeabsolutefixed,則其包含塊為初始包含塊

初始包含塊

根元素(在HTML文件中即<html>元素)所在的包含塊即是初始包含塊,對於瀏覽器來說:初始包含塊的大小即是視口的大小,但是是以畫布原點為錨點的。
瀏覽器的視口是固定在那不變的,但是一個文件可能會很長,可以上下滾動,視口中的內容會不斷變化。初始包含塊可以簡單理解為第一個視口區域(這句話是我自己造的),上圖:

CSS進階——絕對定位元素的寬高是如何定義的

頁面滾動之後:
CSS進階——絕對定位元素的寬高是如何定義的

<!-- demo1 -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>初始包含塊</title>
  <style>
    html {
      margin: 10px;
      padding: 10px;
      border: 1px solid red;
    }
    body {
      padding: 10px;
      border: 1px solid blue;
    }
    .abs {
      position: absolute;
      /*left: 0;*/
      /*bottom: 0;*/
      padding: 5px;
      background-color: #9089e4;
      color: #fff;
    }
  </style>
</head>
<body>
  <h3>絕對定位之初始包含塊</h3>
  <div>
    <div>初始包含塊不是html,也不是body,而是指視口。</div>
    <div>初始包含塊不是html,也不是body,而是指視口。</div>
    <div>初始包含塊不是html,也不是body,而是指視口。</div>
    <div>初始包含塊不是html,也不是body,而是指視口。</div>
    <div>初始包含塊不是html,也不是body,而是指視口。</div>
    <div>初始包含塊不是html,也不是body,而是指視口。</div>
    <div>初始包含塊不是html,也不是body,而是指視口。</div>
    <div>初始包含塊不是html,也不是body,而是指視口。</div>
    <div>初始包含塊不是html,也不是body,而是指視口。</div>
    <div>滾到底啦,沒有更多內容啦~~~</div>
    <div class="abs">我是絕對定位元素。</div>
  </div>
</body>
</html>複製程式碼

CSS進階——絕對定位元素的寬高是如何定義的

函式邊框代表html元素,藍色邊框代表body元素,由gif圖可以進一步加深對初始包含塊的理解:初始包含塊並不是大多數人認為的html或body元素,這是個誤區,要糾正!

絕對定位元素的大小

靜態位置(static position)

一個元素的靜態位置可以簡單理解為這個元素在普通文件流中的位置,就是這個元素的positionstaticfloatnone時,元素在文件中所處的位置。

  • 靜態位置的left值:包含塊的左邊界到當前定位元素的左外邊距(Left Margin)邊界的距離
  • 靜態位置的right值:包含塊的右邊界到當前定位元素的右外邊距(Right Margin)邊界的距離
<!-- demo2 -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>初始包含塊</title>
  <style>
    body {
      position: relative;
      padding: 10px;
      border: 1px solid blue;
    }
    .abs {
      position: absolute;
      margin-left: 5px;
      padding: 5px;
      background-color: #9089e4;
      border: 1px solid orange;
      color: #fff;
    }
    .abs2 {
      position: absolute;
      top: 50px;
      left: 10px;
      margin-left: 5px;
      padding: 5px;
      background-color: #9089e4;
      color: #fff;
      border: 1px solid orange;
    }
  </style>
</head>
<body>
  <div class="abs">絕對定位元素1</div>
  <div class="abs2">絕對定位元素2</div>
  <div>body的其他子元素body的其他子元素body的其他子元素body的其他子元素body的其他子元素body的其他子元素body的其他子元素body的其他子元素body的其他子元素body的其他子元素</div>
</body>
</html>複製程式碼

從上面程式碼可以看出,.abs.abs2兩個元素的靜態位置的left值都為10px(即body的padding-left值),我們不設定.abs的left值,即預設auto,而.abs2的left設定為10px,會看到兩個元素距離包含塊左邊的距離是一樣的。

CSS進階——絕對定位元素的寬高是如何定義的

絕對定位元素的佈局

計算公式(width表示內容寬度,即標準盒子模型):

'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
left、width、right預設值是auto
margin-left、margin-right預設值是0

以水平方向(從左至右:ltr)為例說明一下絕對定位元素的位置(或大小)是如何定義的。起決定因素的有left right width,每個屬性都可以設定或者不設定值,預設為auto,設定了值的在表格中用1表示,總共有2 * 2 * 2 = 8 種情況:

Left Width Right 佈局
auto auto auto 把margin-left和margin-right為auto的設定為0;把left設定為靜態位置的left值;寬度自適應:margin-right邊緣最遠到right為0的位置(如果margin-right為0,則取border-right邊緣,如果border-right-width也為0,則取padding-right邊緣,下同)
1 auto auto 把margin-left和margin-right為auto的設定為0;寬度自適應:margin-right邊緣最遠到right為0的位置
auto auto 1 把margin-left和margin-right為auto的設定為0;寬度自適應:margin-left邊緣最遠到left為0的位置
auto 1 auto 把margin-left和margin-right為auto的設定為0;把left設定為靜態位置的left值
1 1 auto 把margin-left和margin-right為auto的設定為0;從左至右按照各屬性值佈局
auto 1 1 把margin-left和margin-right為auto的設定為0;從右到左按照個屬性值佈局
1 auto 1 把margin-left和margin-right為auto的設定為0;寬度自動拉伸
1 1 1 ① 如果margin-left和margin-right都為auto,此時二者相等,則按照上述方程計算出對應的margin值;如果此時計算出來的margin值為負值,則設定margin-left為0,然後根據方程再計算出margin-right的值。
② 如果margin-left、margin-right中有一個為auto,則按照方程計算出這個值;
③ 如果margin-left、margin-right都設定了值,且導致方程左右不相等,則忽略right值。

上面是以水平方向佈局講述了絕對定位元素的寬度是如何定義的,高度是類似的,就不再詳細闡述了,想進一步瞭解細節的同學請參考 www.w3.org/TR/CSS22/vi…

本文主要參考資料:
www.w3.org/TR/CSS22/vi…


篇幅已經很長了,還有一部分知識點沒講到:

包含塊部分:

  • 絕對定位元素的包含塊是由其最近的position屬性設定為relativeabsolutefixed的祖先元素,按照以下方式生成的:

    • 如果這個祖先元素是行內元素...(包含塊是如何定義的?)

佈區域性分:
上述所講的絕對定位元素的佈局是針對非可替換元素,如果是可替換元素,佈局又是怎樣的?這些內容將在下一篇文章中做進一步闡述。

相關文章