css佈局基礎總結

前端css佈局知識繁雜,實現方式多種多樣。想寫出高效、合理的佈局,必須以深厚的css基礎爲前提。爲了方便記憶和複習,將css佈局要點記錄以下。內容較多,應用方面說的不太詳細,但都是很實用的點。css

所謂佈局,就是指將元素設置爲咱們想要的大小,放置於咱們想要的位置,位置尺寸是核心兩要素。這些元素其實就是一些方塊,頁面就是由各類方塊拼湊而成。如今佈局方式主要分爲三種:html

  • 傳統css佈局方案(position,float,line-height等配合)。實現複雜,須要多種屬性配合使用,兼容性最好。
  • flex佈局方案。彈性佈局,實現方便,兼容性較好。
  • gird佈局方案。

使用哪一種佈局方式,看項目具體要求,若是不須要兼容IE,建議使用flex或者grid,這兩種是將來趨勢。若是要考慮兼容,則最好使用傳統css佈局方案。前端

傳統css佈局方案

css標準盒模型

前面提過,一個html元素,就是一個方塊,講究一點的話就是盒模型。盒模型長這樣:
盒模型chrome

咱們能夠在chrome開發者工具的styles中查看:
盒模型瀏覽器

css盒模型,分爲4部分:ide

  • content:顯示元素內容區域,包含子孫元素的地方
  • padding:內容區域到邊框的距離,也稱內邊距
  • border:顯示自身輪廓
  • margin: 用於設置元素自身和同級元素或者父級元素的距離

規則

無規矩不成方圓。全部的html元素都是按照必定規則去排列渲染的。在html中,不僅有一種規則,是多種規則的混合。瞭解這些渲染規則和這些規則生效的條件對於咱們理解css有很大幫助。工具

文檔流

文檔流能夠理解爲全部元素的默認渲染規則。它的規則很簡單:元素按照本身的類型的佈局特性從左到右,從上往下依次排列。佈局

元素在佈局上分爲三種類型:字體

  • 塊級元素:默認佔據一整行,即時設置寬度也仍是佔據一整行,由margin來補充(霸道總裁),有block、table、flex、grid、list-item
  • 內聯元素:寬度由內容撐開,只佔據本身的位置,即時設置了寬度也不起做用,margin也是左右起做用,上下不起做用(你們閨秀),有inline
  • 內聯塊級元素: 寬度由內容撐開,只佔據本身的位置,能夠設置本身的寬度(兩我的的孩子?),有inline-block、inline-table、inline-flex、inline-grid

上面內聯元素其實說的不太正確,這裏須要特殊說一下,內聯元素又分爲兩種:flex

  • 可置換內聯元素:該元素展現的內容不在css做用域範圍以內,典型好比img、video、object、input、textarea等,展現內容由src、value等決定,這種元素能夠設置寬高
  • 不可置換內聯元素:普通的內聯元素,好比span、a、i、em等

有兩種方式能夠脫離文檔流,絕對定位和浮動,咱們下面再詳細說。

BFC

BFC全稱是Block Formatting Context,塊級格式化上下文。在BFC環境中的元素按照以下規則渲染:

  • 和文檔流同樣,元素按照本身類型的佈局特性從左到右,從上往下依次排列。
  • BFC是一個獨立、封閉的渲染區域。子元素的樣式對BFC外部產生影響。
  • BFC能夠識別浮動子元素。
  • BFC能夠識別浮動的同級元素。利用這一點能夠製做彈性佈局。

那麼什麼樣的渲染區域是一個BFC哪?下列幾種方式能夠顯示聲明一個BFC的渲染區域:

  • 根元素或包含根元素的元素
  • float的值不爲none
  • position爲absolute或者fixed
  • overflow的值不爲visible
  • display爲inline-block、table-cell、table-caption

尺寸

元素的尺寸有兩種狀況:

  • 默認狀況: 塊級元素寬度默認爲100%,高度由內容撐開;內聯元素和內聯塊級元素寬度和高度默認由內容撐開。
  • 開發者設置: 主動設置width、height、line-height等

咱們先來明確一下元素的尺寸概念,咱們都知道元素的盒模型,元素由content、padding、border、margin四個區域組成。那麼尺寸具體是指什麼?咱們能夠把尺寸分爲三類:

  • 元素尺寸:由content、padding、border組成,在原生的DOM API中用offsetWidth、offsetHeight獲取
  • 元素內部尺寸: 由content、padding組成,在原生的DOM API中用clientWidth和clientHeight獲取
  • 元素外部尺寸: 由content、padding、border、margin組成,沒有對應的DOM API,可是理解這個,對佈局頗有幫助

而咱們在css中設置的width、height表明哪部分區域是有歧義的,咱們經過設置box-sizing,能夠切換width、height所表明的區域。

box-sizing

box-sizing,能夠切換width、height所表明的區域。box-sizing主流瀏覽器有兩個值:

  • content-box: width、height設置的是content的寬高
  • border-box: width、height設置的是content、padding、border加起來的寬高

box-sizing的這兩個屬性,形成width、height的二義性,並且不少狀況下是全局設置的,隱蔽性很強,對於新手來講很容易懵。這兩個屬性的產生有必定的歷史緣由,最開始的盒模型默認採用的border-box,早期的IE就是這種,也叫IE盒模型。後來W3C以爲content-box更好,又把盒模型默認改成content-box模式。後來的後來,隨着彈性佈局的流行,border-box的優點愈來愈明顯,你們都更願意使用border-box來佈局,W3C又想把border-box搞回來。可是已經有好多基於content-box的網站,爲了兼容性也不能隨便改。因而,W3C就想出了box-sizing這種方式,支持了border-box,可是默認仍是content-box。使用box-sizing應注意的幾點:

  • 加入要全局設置box-sizing: border-box,要注意對第三方組件庫的侵入,由於第三方組件極可能是基於content-box來佈局的
  • 設置全部元素的box-sizing屬性爲inherit:

    *, *:before, *:after {
        box-sizing: inherit;
    }

    這樣咱們能夠設置父元素的box-sizing,就能夠控制全部子元素的box-sizing屬性,對於咱們封裝組件,設置整個組件環境很方便,只有咱們在封裝組件時強設置box-sizing,就不怕全局的樣式侵入了。

  • content-box模式在設置彈性佈局時,可使用calc屬性輔助實現,或者弄兩層div實現

尺寸的百分比設置

包含塊

咱們知道width, height都是能夠設置百分比,那這個百分比的參照物是誰?這裏引出一個概念,叫作包含塊(CB, Contanining Block),一個元素的包含塊就是該元素的width、height百分比的參照物。

不少新手同窗,在設置寬高百分比的時候,有時候以爲莫名其妙,各類奇怪現象,怎麼設置都不起做用。其實就是沒有包含塊的概念。一個元素的包含塊是誰,主要取決於該元素的position屬性,總結以下:

  • position爲static和relative的元素,包含塊爲其父元素的content-box
  • position爲absolute的元素,包含塊爲其最近的定位非static的祖先元素的padding-box,若是沒有定位非static的祖先元素,則爲初始包含塊(後面解釋)
  • position爲fixed的元素,包含塊爲視口viewport
  • position爲absolute和fixed時,包含塊也多是由知足如下條件的最近父級元素的padding-box:

    1. A transform or perspective value other than none
    2. A will-change value of transform or perspective
    3. A filter value other than none or a will-change value of filter (only works on Firefox)

這條比較特殊,遇到的狀況比較少,單獨拿出來

除了width, height的百分比相對於包含塊設置外,margin、padding的百分比也是相對於包含塊設置,只不過margin、padding百分比相對於包括塊的寬度設置(水平模式下)。絕對定位的偏移屬性top、left、right、bottom也是相對於包含塊設置,後面再詳細說。

初始包含塊

元素的包含塊都是本身的祖先元素,那hmtl元素沒有祖先元素,它的百分比設置相對於誰那?就是初始包含塊,根元素(hmtl)所在的包含塊是一個被稱爲初始包含塊的矩形。這個矩形的大小就是瀏覽器視口的大小。有一點須要注意,那些沒有定位非static祖先元素的參照物是初始包含塊,而非html元素。

margin

由於margin在佈局中有一些重要特性和特殊狀況,因此單獨拿出來說一下。

margin:auto

咱們知道,塊級元素即便設置了寬度,也會佔滿一行,爲何會這樣?剩餘的空間被誰佔了?

這裏要明確一點,塊級元素佔據一行,是指塊級元素的外部尺寸佔據一行,就是margin-box。當margin設置爲auto的時候,margin會自動佔滿剩餘空間。

  • margin-left: 默認爲0,爲auto時,自動充滿剩餘空間
  • margin-right: 默認爲0,爲auto時,自動充滿剩餘空間
  • margin-top: 默認爲0,爲auto時,值仍是爲0
  • margin-bottom: 默認爲0,爲auto時,值仍是爲0

當margin-left和margin-right同時爲auto,就會平分剩餘空間,這就是margin:auto會使元素水平居中的緣由。而後margin: auto卻不能使元素垂直居中,這是由於在垂直方向上,塊級元素不會自動擴充,它的外部尺寸沒有自動充滿父元素,也沒有剩餘空間可說。若是咱們在父元素上設置writing-mode: vertical-lr,這時margin:auto就會使子元素垂直居中,而水平居中無效。

那有沒有什麼辦法使用margin:auto讓元素同時水平垂直居中?答案是有的,就是絕對定位的狀況下。

.father {
    width: 300px; height:150px;
    position: relative;
}
.son {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    width: 200px;
    height: 200px;
    margin: auto;
}

此時的son的外部尺寸,就會自動充滿它的包含塊,效果和塊級元素相似。這時候設置.son元素的寬高,就會有剩餘空間出來,margin:auto會自動平分剩餘空間,使.son水平垂直居中。

margin對佈局影響

margin對元素的影響有2個:

  • 影響內部尺寸
  • 影響外部尺寸
影響元素內部尺寸

塊級元素這種寬度方向自動充滿空間的佈局特性,當沒有設置寬度,設置margin-left和margin-right爲對元素的內部空間有影響。margin爲正值時,元素尺寸縮小;margin爲負值時,元素尺寸增大。由於元素的外部尺寸大小已經定了,就是其包含塊的尺寸,而外部尺寸等於元素尺寸加上margin,若是margin爲負,元素尺寸天然就增大了。利用內部尺寸增大、外部尺寸不變這個特色,咱們能夠進行等間隔列表的佈局。好比咱們實現一個一行三列,兩側無間隙,中間間隙爲20px的佈局:

.father{
    margin-right: -20px;
}
.son{
    width: calc( calc(100% - 20px * 3) / 3);
    margin-right: 20px;
}
影響元素外部尺寸

在元素寬高固定的時候,至關於元素尺寸固定了,margin開始影響元素的外部尺寸。正margin會使元素元素的外部尺寸增大,負margin會使元素元素的外部尺寸縮小。正值很好理解,就不說了。主要說一下負值,這時候margin-top、margin-left和margin-right、margin-bottom的表現看起來是有區別的,實質是同樣。margin-top、margin-left爲負值時,表現爲元素向上或者向左移動,margin-right、margin-bottom爲負值時,表現爲其右側元素或者下面元素都會相應地向左或者向上移動。仔細想一想,這都是元素外部尺寸縮小的表現。margin-top、margin-left使左側上上側尺寸縮小,就會天然向左或者向上移動。margin-right、margin-bottom使右側和下側尺寸縮小,旁邊和下面的元素天然就會往左或者往上佔位。

margin合併

塊級元素的上邊距和下邊距在某些場景下會發生合併行爲。須要注意的是浮動元素和絕對定位元素不會發生合併,且合併只發生在垂直方向。有如下3中合併場景

  • 相鄰兄弟元素
  • 父元素和第一個/最後一個元素
  • 元素內容爲空時,height爲0,本身的上邊距和下邊距會發生合併

margin合併的計算規則

  • 正正取大
  • 正負相加
  • 負父取小(-20px, -50px合併取-50px)

阻止margin合併的方法

  • 把合併元素變成BFC,好比設置display: inline-block,overflow: hidden, float: left等
  • 父子合併/空元素合併時,給父元素/空元素設置border、padding都能阻止合併

內聯元素尺寸

主要想說line-height,vertical-align兩個屬性,這兩個屬性對高度有重要的影響,並且若是沒有理解這兩個屬性的做用,會常常碰到一些很差解決的詭異的佈局問題。

幽靈空白節點

這個名字是張鑫旭大神定義的,在W3C規範中也是能夠找到根據的。在《CSS世界》這本書中,爲了證實幽靈空白節點的存在,舉了一個例子:

div {
    background-color: #cd0000;
}
span {
    display: inline-block;
}
<div><span></span></div>

你可能猜到了,div的高度不爲0,我在chrome下試了試高度爲21px,這個高度猜想應該和div的字體、字體大小、行高有關。這個幽靈空白節點的存在,會引發一些怪異現象,好比:

<div><img></img></div>

div的高度老是比img高一些,img下總有一個間距。這也是一個幽靈空白節點在起做用。

line-height

line-height翻譯過來就是行高。它指的是指行框的高。那什麼是行框那?

行框是由內聯元素或者內聯塊級元素組成的一行。經過嘗試,發現一行造成行框的兩個前提是,要麼有文字內容,要麼有內聯塊級元素,若是其中是一堆空的內聯元素,好比span,是沒有造成行框的。

line-height就是指定行框佔據的高度。只有造成了行框,line-height纔會起做用。

這裏可能有一些容易誤解的狀況,好比:

.father{
    line-height: 300px;
}
<div class="father">
    <div class="son">
        你好
    </div>
</div>

這時候.fahter高度是300px,這裏注意的是,不是line-height對.son起做用了,是.son內部造成了一個行框,line-height對這個行框起做用了,.son的高度是300px,撐開了.father。

vertical-align

vertical-align用來設置內聯元素或者內聯塊級元素在行框內的對齊方式或者說垂直位置。verticle-align有四類值,咱們在這裏直說其中對佈局比較重要的兩類:

  • 線類: baseline(默認值)、top、middle、bottom
  • 數值類:好比20px、20em
基線

先來看一張圖:

基線

vertical-align默認是基線對齊的,基線的位置很重要。而基線的定義是:字母x的下邊緣。中線的位置是基線往上 1/2 x-height 高度,就是x交叉的地方。這裏有一個須要注意的地方是,純文字的中線是x交叉的地方,可是內聯元素的中線倒是內聯元素的正中間位置。咱們來看一個例子:

div{
  line-height: 100px;
  background: yellow;
}
<div>
  <span class="world">xhello</span>
</div>

效果以下:
正常高度

一切正常,div高度100px,文字也是近似垂直居中。可是若是咱們在.world元素上加vertical-align: middle,咱們會發現文字向下偏移,且div高度變成了102px,效果以下:
不正常高度

這是怎麼回事那,vertical-align設置的到底跟誰對齊?答案是幽靈空白節點,幽靈空白節點是個很神奇的存在,看不見,但卻實實在在地在起做用,它的做用就至關於一個x字符的做用,用來提供對齊基準。咱們上面說到的,div元素中有一個圖片的例子,img是可替換內聯元素,它的baseline就是它的底部,默認是baseline對齊,因此圖片對齊的是幽靈空白節點x的基線,x基線位置往下是一段空白的,這就是這段空白的來源。爲了更直觀,咱們在上面這個例子的span元素前面加一個x字符,當作幽靈空白節點,看一下效果:
不正常高度

原本,xxhello中的x是對齊的。設置vertical-align以後,咱們能夠看到xhello字符向下挪了一段位置,這是由於span元素的垂直中線位置,比xhellox交叉點要高,如今要和前面的x交叉點對齊,就往下移動了。又由於xxhello的行高都是100px,可是如今由於因爲錯位,形成總體高度多了2px。

垂直居中應用

利用line-height和vertical-align能夠設置多種場景下的垂直居中。

  • 單行居中
div{
    line-height: 任意值
}
<div>hello world</div>
  • 父元素定高垂直居中,這個在.box上設置line-height實際上設置了幽靈空白節點的行高是120px,而後.content和幽靈空白節點middle對齊就實現了垂直居中。
.box {
    line-height: 120px;
    background-color: #f0f3f9;
}
.content {
    display: inline-block;
    line-height: 20px;
    margin: 0 20px;
    vertical-align: middle;
}
<div class="box">
    <div class="content">多行文字...</div>
</div>
  • 父元素不定高垂直居中,原理其實和父元素定高狀況相同,可是由於不定高,你無法設置父元素的line-height,這時候咱們能夠設置一個父元素的僞元素,設置成高度100%,vertical:middle,由於元素是從左上向下排列,因此vertical:middle會把幽靈空白節點的x拉到父元素垂直中心位置。這時候,咱們再設置子元素的vertical-align:middle就達到了目的。
.container {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0;
    background-color: rgba(0,0,0,.5);
}
.container:after {
    content: '';
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}
.dialog {
    display: inline-block;
    vertical-align: middle;
}
<div class="container">
    <div class="dialog"></dialog>
</div>

位置

元素的位置由position屬性和float屬性決定。

position屬性

position有4個值:

  • static: 默認值,按照css規則排列
  • relative:相對定位,可設置偏移量,top,left,right,bottom,偏移量百分比大小的參照物是其包含塊,偏移量的位置參照物是自身位置
  • absolute:絕對定位,可設置偏移量,top,left,right,bottom,偏移量百分比大小和位置的參照物是其包含塊
  • fixed:固定定位,可設置偏移量,top,left,right,bottom,偏移量百分比大小和位置的參照物是其包含塊viewport

須要注意的地方有:

  • position爲relative、absolute、fixed時,若是不設置偏移量,默認位置爲文檔流的正常位置
  • position爲absolute、fiexed的元素,脫離文檔流,文檔流中的元素不識別該元素,不識別它的佔位和寬高度(不是自家孩子)
  • position爲absolute、fiexed的元素,寬度的渲染規則和內聯塊級元素相同,寬度默認爲由內容撐開,可設置寬高

float屬性

float屬性可使元素脫離文檔流,向左或者向右移動,直至碰到包含塊的padding或者碰到另外一個浮動元素。注意:

  • position爲absolute、fixed會讓浮動屬性失效
  • float會使元素塊狀化,dispaly的值,inline-table變爲table,剩下的都變爲blcok,可是元素寬度的渲染規則和內聯塊級元素相同,寬度默認爲由內容撐開,可設置寬高

float最著名的就是它的高度坍塌,之因此有高度坍塌,和float設計的初衷有關。float屬性最初是設計用來實現文字環繞效果的。

<div class="img-wrap">
    <img style="float: left"/>
</div>
<p>我是文字,我要環繞你</p>

.img-wrap由於高度塌陷,實際上不識別float元素,高度爲0,p元素與其重合,從而實現文字環繞效果。

高度塌陷特性在實現佈局的時候是不合理的,而如今文字環繞的場景不多,float基本都用來佈局使用了。這如今實際上已經成爲了一個「bug」的存在。因此css又提供了一個屬性用來清除浮動:clearfix。

clearfix

clearfix在mdn上的解釋爲指定一個元素是否能夠在它以前的浮動元素旁邊(我以爲這裏用重合更貼切),或者必須向下移動(清除浮動) 在它的下面。

注意上面這句話,指定一個元素表示clearfix的做用目標是元素自身,在它以前的浮動元素表示clearfix的做用條件是它前面有浮動元素,而clearfix的做用效果是讓元素換行顯示。因此clearfix的做用是,若是元素前面有浮動元素,能夠指定該元素換行顯示,或者說是識別前面的浮動元素。clearfix有3個值:

  • left: 清除左浮動
  • right: 清除右浮動
  • both: 清除左右浮動

通常狀況下采用clearfix: both。清除浮動一個重要應用就是解決float高度塌陷的問題。通用的解決方案是設置.clearfix類:

.clearfix {
    display: block;
    zoom: 1;
    &:after {
        content: "";
        display: block;
        font-size: 0;
        height: 0;
        clear: both;
        visibility: hidden;
    }
}

在包含浮動元素的父元素上設置該類便可。

博客地址

參考

相關文章
相關標籤/搜索