CSS 中的 float、BFC、position 和 inline-block

wopen發表於2019-04-09

CSS 中有時候需要一些特殊佈局,用正常流做不出來的效果。這時我們就可以使用破壞流和保護流的那些 CSS 屬性來實現這些效果。

float

float 屬性指定一個元素應沿其容器的左側或右側放置,允許文字和內聯元素環繞它。該元素從網頁的正常流(文件流)中移除,儘管仍然保持部分的流動性(與絕對定位相反)。

當一個元素浮動之後,它會被移出正常的文件流,然後向左或者向右平移,一直平移直到碰到了所處的容器的邊框,或者碰到另外一個浮動的元素。

float最初的設計目的是為了實現文字環繞效果,主要指的就是文字環繞圖片顯示的效果。所以就導致我們用它實現一些複雜的佈局時問題一大堆。所以能不用float佈局就不用。

float主要有 3 個屬性值none, leftright

當一個元素浮動時它具有以下特性:

  • 包裹性 - 浮動元素會包裹它的子元素(浮動元素子元素 100x100,則浮動元素也是 100x100)
  • 自適應 - 如果浮動元素子元素有一堆文字時,它的最終寬度為它的父級寬度。
  • 塊狀話並格式化上下文 - float的屬性值不為none,則其display計算值就是block 或者table
  • 破壞文件流 - 會讓父元素的高度塌陷
  • 沒有margin合併

float還有一個特性是行框盒子和浮動元素的不可重疊,正常定位狀態下只會跟隨浮動元素,而不會發生重疊。

<div>
  <img src="http://">
</div>
<p>文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字</p>
<style>
div {padding-top: 10px; background: #ccc;}
img { width: 100px; float: left;}
</style>
複製程式碼

CSS 中的 float、BFC、position 和 inline-block

我們可以看到pimg重疊了,但是p中的行框盒子則是跟隨浮動元素。

流體佈局

float可以很方便的實現多欄佈局。

<div class='page'>
  <div class="float">
    <p>float</p>
  </div>
  <div class="a">
    文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字
  </div>
</div>
<style>
.float { float: left; width: 60px;background: green;}
.a { margin-left: 70px; background: red; }
</style>
複製程式碼

CSS 中的 float、BFC、position 和 inline-block

<div>
  <div class="l">left</div>
  <div class="r">right</div>
  <h1>title</h1>
</div>
<style>
.l { float: left; } 
.r { float: right; }
h1 { margin: 0 50px; text-align: center;}
</style>
複製程式碼

CSS 中的 float、BFC、position 和 inline-block

清除浮動

clear屬性是專門來處理float帶來的高度塌陷等問題的。 它指定一個元素是否必須移動(清除浮動後)到在它之前的浮動元素下面。clear屬性適用於浮動和非浮動元素。

它一共有 4 個值,noneleftrightboth

其中leftright是沒什麼作用的,因為在要使用leftright的情況下都可以使用both替換。

clear屬性是讓自身不能和前面的浮動元素相鄰,它對後面的元素是不管的,leftright是不能同時存在的。

clear屬性只有塊級元素才有效的,所以我們用::after偽類時都要將它的display設定為block

.clear:after {
    content: '';
    display: block;
    clear: both;
}
複製程式碼

clear其實並沒有清除浮動而是讓自己不和float元素在一行顯示。

<div class="page">
    <img src="https://">
    文字文字文字文字文字文字
</div>
<div>
    文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字
</div>
<style>
.page:after {
    content: '';
    display: table;
    clear: both;
}
.page img {
    float:left;
    width: 100px;
}
.page + div {
    margin-top: -2px;
}
</style>
複製程式碼

CSS 中的 float、BFC、position 和 inline-block

可以看到雖然使用了clear,但是clear後面的元素任有可能受float的影響。

BFC

塊格式化上下文(Block Formatting Context,BFC) 是 Web 頁面的視覺化 CSS 渲染的一部分,是塊盒子的佈局過程發生的區域,也是浮動元素與其他元素互動的區域。

BFC 就像結界,它會形成一個封閉的空間,裡面的子元素不會影響到外面的元素,所以 BFC 也可以用來清除浮動。

在以下情況下會觸發 BFC:

  • 根元素或包含根元素的元素
  • 浮動元素(元素的float不是none
  • position的值不為relativestatic
  • overflow值不為visible的塊元素
  • display的值為table-celltable-captioninline-block中的任何一個
  • 彈性元素和網格元素

流體佈局

BFC 可以實現更健壯、更智慧的自適應佈局。

<div>
    <div></div>
    <p>文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字</p>
</div>
<style>
div > div {
  width: 50px;
  height: 50px;
  float: left;
  background: red;
}

p { overflow: hidden; }
</style>
複製程式碼

CSS 中的 float、BFC、position 和 inline-block

普通流體元素在設定了overflow:hidden後,會自動填滿容器中除了浮 動元素以外的剩餘空間,形成自適應佈局效果。

overflow

overflow是最適合清除浮動影響的元素,而不是clear。但是它的本職工作還是裁剪。它是overflow-xoverflow-y的簡寫屬性。

overflow裁剪是沿著border內邊緣裁剪的。

<div>
  <p>文字文字文字文字文字文字文字文字文字文字文字文字</p>
</div>
<style>
div {
  border: 10px solid;
  padding: 10px;
  overflow: hidden;
}
p {
  white-space: nowrap;
}
</style>
複製程式碼

CSS 中的 float、BFC、position 和 inline-block

它常用屬性有:

  • visible 預設值。內容不會被修剪,會呈現在元素框之外
  • hidden 內容會被修剪,並且其餘內容不可見
  • scroll 內容會被修剪,瀏覽器會顯示滾動條以便檢視其餘內容,滾動條區域一直在
  • auto 由瀏覽器定奪,如果內容被修剪,就會顯示滾動條

overflow-xoverflow-y

overflow-xoverflow-y屬性中的一個值設定為visible而另 外一個設定為scrollautohidden,則visible的樣式表現會如同auto

也就是說永遠不可能實現一個方向溢位剪裁或滾動,另一方向內容溢位顯示的效果。

滾動條

HTML 中只有兩個標籤預設可以產生滾動條,htmltextarea,因為它們的overflow不是visible

滾動欄佔據寬度的特性最大的問題就是頁面載入的時候水平居中的佈局可能會產生晃動,因為窗體預設是沒有滾動條的,而 HTML 內容是自上而下載入的,就會發生一開始沒有 滾動條,後來突然出現滾動條的情況,此時頁面的可用寬度發生變化,水平居中重新計算,導 致頁面發生晃動。

這裡有一個防止晃動的小技巧。

html {
    overflow-y: scroll; /* for IE8 */
}
:root {
    overflow-y: auto;
    overflow-x: hidden;
}
:root body {
    position: absolute;
}
body {
    width: 100vw;
    overflow: hidden;
}
複製程式碼

對於支援-webkit-字首的瀏覽器,我們可以用以下偽類自定義滾動條。

  • ::-webkit-scrollbar 整體部分
  • ::-webkit-scrollbar-button 兩端按鈕
  • ::-webkit-scrollbar-track 外層軌道
  • ::-webkit-scrollbar-track-piece 內層軌道
  • ::-webkit-scrollbar-thumb 滾動滑塊
  • ::-webkit-scrollbar-corner 邊角
::-webkit-scrollbar {
  width: 8px;
}
::-webkit-scrollbar-thumb {
  background-color: rgba(0,0,0,.3);
  border-radius: 10px;
}
::-webkit-scrollbar-track {
  background-color: transparent;
  border-radius: 10px;
}
複製程式碼

CSS 中的 float、BFC、position 和 inline-block

文字溢位

CSS 中有很多屬性要想生效都必須要有其他 CSS 屬性配合。比如文字溢位顯示...

.ell {
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
    /* 這 3 個宣告缺一不可 */
}

/* 多行文字省略,無需依賴 overflow */
.ell2 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
}
複製程式碼

錨點定位

一般實現錨點定位有兩種方法,一種是使用ahrefname屬性,如:

<a href="#1">Title ></a>
<a name="1">Title</a>
複製程式碼

還有一種是使用ahref和其他元素的id屬性。

<a href="#1">Title ></a>
<h2 id="1">Title</h2>
複製程式碼

它的原理是當我們點選一個連結,改變了位址列的 hash 值,而且這個 hash 值可以在頁面中找到對應的元素,並且是非隱藏狀態,否則不會發生定位行為。

我們也可以使用一個簡單的#來實現返回頂部功能,它可以將頁面是定位到頂部。

錨點定位行為的發生,本質上是通過改變容器滾動高度或者寬度來實現的。水平和垂直方向一樣,一般發生垂直滾動的多。

錨點定位也可以發生在普通的容器元素上,而且定位行為的發生是由內而外的。由內而外指的是,普通元素和窗體同時可滾動的時候,會由內而外觸發所有可滾動窗體的錨點定位行為。

<div>
  <div class="overflow">
    <p>文字</p>
    <p>文字</p>
    <p>文字</p>
    <h2 id="1">Title</h2>
  </div>
  <a href="#1">title ></a>
  <div style="height: 500px;"></div>
</div>
<style>
.overflow {
  overflow: hidden;
  height: 2em;
  background: #ccc;
}
</style>
複製程式碼

CSS 中的 float、BFC、position 和 inline-block

CSS 中的 float、BFC、position 和 inline-block

我們發現overflow滾動到了h2元素位置(雖然沒有滾動條),頁面的滾動條也滾動到了可以顯示h2元素的位子。

用這個特點我們可以實現一個無需js的幻燈片效果。但是當我們點選切換按鈕的時候,頁面的滾動條也會自動滾動。

這時候我們就可以使用focus錨點定位,它是利用labelfor屬性和inputid屬性。

<div>
    <div><input id="one">1</div>
    <div><input id="two">2</div>
    <div><input id="three">3</div>
</div>
<div>
    <label for="one">1</label>
    <label for="two">2</label>
    <label for="three">3</label>
</div>
複製程式碼

除了點選按鈕切換,我們還可以使用tab鍵切換。

position

position屬性用於指定一個元素在文件中的定位方式。toprightbottomleft屬性則決定了該元素的最終位置。

position一共有 5 個值:

  • static 正常的佈局行為,即元素在文件常規流中當前的佈局位置。
  • relative 元素先放置在未新增定位時的位置,再在不改變頁面佈局的前提下調整元素位置
  • absolute 脫離正常文件流,通過指定元素相對於最近的非static定位祖先元素的偏移,來確定元素位置
  • fixedabsolute類似,但是它是相對於螢幕視口的位置來指定元素位置。
  • sticky 盒位置根據正常流計算,然後相對於該元素在流中的 flow root(BFC)和最近的塊級祖先元素定位。在所有情況下,該元素定位均不對後續元素造成影響。

定位元素的型別主要有:

  • 相對定位元素 - 是計算後位置屬性為relative的元素。
  • 絕對定位元素 - 是計算後位置屬性為absolutefixed的元素。
  • 粘性定位元素 - 是計算後位置屬性為sticky的元素。

absolute

absolute定位和overflow的裁剪類似,它的定位是相對於祖先定位元素的padding box的。

absolute相對於最近的position不為static的祖先元素定位,如果沒有的話,就像對於html定位。

當一個元素設定了absolute時候,它的float屬性是無效的。

absolutefloat類似它們有幾個共同點:

  1. 當元素設定了position後也會發生塊狀化display的計算值就是blocktable
  2. absolute會破壞正常的流來實現自己的特性表現,但本身還是受普通的流體元素佈局。
  3. absolute也可以 BFC
  4. absolute也具有包裹性

無依賴定位

無依賴定位定位指的是,absolute定位,不依賴left, right, top, bottom和設定父元素為relative,來實現元素定位。

absolute定位元素的位置和沒有設定absolute時的位置有關。所以我們可以通過調整元素的margin來調整元素的無依賴定位。

absolute 與 overflow

如果overflow不是定位元素,同時絕對定位元素和overflow容器之間也沒有定位元素,則overflow無法對absolute元素進行剪裁。

<div style="overflow: hidden;">
    <img src="a.jpg" style="position: absolute;">
    <!-- 不會被剪裁 -->
</div>


<div style="overflow: hidden; position: relative;">
    <img src="a.jpg" style="position: absolute;">
    <!-- 被剪裁 -->
</div>

<div style="overflow: hidden;">
    <div style="position: relative;">
        <img src="a.jpg" style="position: absolute;">
        <!-- 被剪裁 -->
    </div>
</div>
複製程式碼

如果overflow的屬性值不是hidden而是auto,即使絕對定位元素高寬 比overflow元素高寬還要大,也都不會出現滾動條。

流體特性

absolute元素的left/top/right/bottom屬性都設定的時候,absolute元素才真正變成 絕對定位元素。它會格式化元素的寬度和高度。

.box {
    position: absolute;
    left: 0; right: 0; top: 0; bottom: 0;
}
複製程式碼

如果box父定位元素是html的話,它的寬和高會隨著瀏覽器視窗大小變化而變化。

當絕對定位元素處於流體狀態的時候,各個盒模型相關屬性的解析和普通流體元素都是一 模一樣的,並且可以使用margin:auto讓絕對定位元素保持居中。

絕對定位元素的margin:auto規則和普通流體元素的一樣:

  • 如果一側定值,一側autoauto為剩餘空間大小;
  • 如果兩側均是auto,則平分剩餘空間。
.box {
  width: 300px; height: 200px;
  position: absolute;
  left: 0; right: 0; top: 0; bottom: 0;
  margin: auto;
  background: red;
}
複製程式碼

這行程式碼就可以讓box水平垂直居中。

relative

我們一般用relative來限制absolute定位。讓它相對於設定了relative的祖先容器定位。

relative是相當於自己當前的位置定位,一般情況下它不會影響到周圍的元素。

relative同時設定了leftrighttopbottom時,它不會和absolute一樣格式化寬高,而是根據文件流的方向,一個有效而另一個會無效。

fixed

fixed定位的包含塊只有一個html根元素,fixedabsolute一樣也可使用無依賴定位。

sticky

粘性定位,就好像是relativefixed的結合體。元素在螢幕內,表現為relative,就要滾出顯示器螢幕的時候,表現為fixed

sticky有以下特點:

  1. sticky的父級元素的overflow只能是visible,否則會沒有效果。
  2. 同一個父容器中的sticky元素,如果定位值相等,則會重疊;如果屬於不同父元素,則會擠開原來的元素,形成依次佔位的效果。

inline-block

inline-blockdisplay的一個屬性值,它可以讓元素和行內元素一樣在一行顯示,又可以和塊級元素一樣設定寬高。

空隙

使用inline-block有點小問題,那就是inline-block元素間有空格或是換行產生了間隙。

<style>
<div></div>
<div></div>
div {
  display: inline-block;
  width: 100px;
  height: 100px;
  background: red;
}
</style>
複製程式碼

CSS 中的 float、BFC、position 和 inline-block

空格相當於字元,那麼我們可以使用font-size: 0;去除它們之間的空隙。

除了font-size我們還可以使用letter-spacing,它用來設定字元之間的空隙寬度。我們可以設定word-spacing: -1em;來去除inline-block之間的空隙。

我們還可以使用word-spacing,它用來設定單詞間距,它和letter-spacing相似,我們設定它為負值來去除空隙。

YUI 3 CSS Grids 是這樣去除inline-block之間的空隙的。

.yui3-g {
    letter-spacing: -0.31em; /* webkit */
    *letter-spacing: normal; /* IE < 8 */
    word-spacing: -0.43em; /* IE < 8 && gecko */
}

.yui3-u {
    display: inline-block;
    zoom: 1; *display: inline; /* IE < 8 */
    letter-spacing: normal;
    word-spacing: normal;
    vertical-align: top;
}
複製程式碼

相關文章