碎碎念
CSS的學習入門很容易,只要1年甚至半年的時候,我們就能根據設計圖迅速切出頁面,能熟練使用些CSS hack,這個階段我們的成長很快,每天都能汲取新知識。這實際上是CSS非常初級的階段,也是廣大頁面仔們(包括我本人?)最為浮躁,最自以為是,最覺得CSS不過如此的階段。所以我們要增加學習的深度,深入掌握細節和原理,當我們對CSS的底層表現有一定的理解與認識的時候,遇到一些看似奇怪的問題,可以輕鬆搞定~
佈局
我們在研究佈局之前,首先需要了解幾個很重要的概念和屬性:
文件流
文件流指的是元素排版佈局過程中,元素會自動從左往右,從上往下的流式排列。並最終窗體自上而下分成一行行,並在每行中從左至右的順序排放元素。HTML中全部元素都是盒模型,盒模型佔用一定的空間,依次排放在HTML中,形成了文件流。
float
、position:absolute|fixed
是脫離文件流的。脫離文件流是指,這個標籤脫離了文件流的管理。不受文件流的佈局約束了,並且更重要的一點是,當一個元素脫離文件流後,這個標籤在原文件流中所佔的空間也被清除掉了,依然在文件流中的其他元素將忽略該元素並填補其原先的空間。
塊級元素
- 每個塊級元素都是獨自佔一行,其後的元素也只能另起一行,並不能兩個元素共用一行。
- 元素的高度、寬度、行高和頂底邊距都是可以設定的。
- 元素的寬度如果不設定的話,預設為父元素的寬度
- 常見的塊級元素:
<div>、<p>、<h1>...<h6>、<ol>、<ul>、<dl>、<table>、<address>、<blockquote> 、<form>
行級元素
- 可以和其他元素處於一行,不用必須另起一行。
- 元素的高度、寬度及頂部和底部邊距不可設定。
- 元素的寬度就是它包含的文字、圖片的寬度,不可改變。
- 常見的行級元素:
<span>、<a>、<strong>、<em>
行級元素與塊級元素的轉換
- 可以在css樣式中用display:inline將塊級元素設為行級元素
- 同樣,也可以用display:block將行級元素設為塊級元素
display
是CSS中最重要的用於控制佈局的屬性,每個元素都有一個預設的值,這與元素的型別有關。對於大多數元素它們的預設值通常是block
(塊級元素)或inline
(行內元素)。
display:none
和visibility
屬性不一樣。display:none
的元素不會佔據它本來應該顯示的空間,但是設定成visibility: hidden;
還會佔據空間。
外邊距摺疊
如果兩個相鄰元素都在其上設定外邊距,並且兩個外邊距接觸,則兩個外邊距中的較大者保留,較小的一個消失
定位(position)
-
static:預設值。元素框正常生成。塊級元素生成一個矩形框,作為文件流的一部分;行內元素則會建立一個或多個行框,置於其父元素中。
-
relative:元素框相對於之前正常文件流中的位置發生偏移,並且原先的位置仍然被佔據。發生偏移的時候,可能會覆蓋其他元素。
- absolute:元素框不再佔有文件流位置,並且相對於包含塊進行偏移(所謂的包含塊就是最近一級外層元素position不為static的元素),找不到符合條件的父(祖先)節點,則相對瀏覽器視窗進行定位;沒有設定TRBL,則預設浮動,預設浮動在父級節點的content-box區。
- fixed:屬性的值為fixed的元素會相對於視窗來定位,即便頁面滾動,它還是會停留在相同的位置。一個固定定位元素不會保留它原本在頁面應有的空隙(即脫離文件流),但是移動裝置相容性不好。
- sticky:(這是css3新增的屬性值)粘性定位,官方的介紹比較簡單。其實,它就相當於relative和fixed混合。最初會被當作是relative,相對於原來的位置進行偏移;一旦超過一定閾值之後,會被當成fixed定位,相對於視口進行定位。
浮動(float)
最初,設計浮動時,其實並不是為了佈局的,而是為了實現文字環繞的特效。類似於ps中的圖層一樣,浮動的元素會在浮動層上面進行排布,而在原先文件流中的元素位置,會被以某種方式進行刪除,但是還是會影響佈局,所以要記得清除浮動。
浮動為什麼會被使用在佈局中呢?因為設定浮動後的元素會形成BFC(使得內部的元素不會被外部所干擾),並且元素的寬度也不再自適應父元素寬度,而是適應自身內容。這樣就可以,輕鬆地實現多欄佈局的效果。浮動通常用於建立多個列布局,並且由於它有良好的瀏覽器相容性,已經被使用了相當一段時間。
flex佈局
彈性佈局:用來為盒狀模型提供最大的靈活性,採用 Flex 佈局的元素,稱為 Flex 容器(flex container)。它的所有子元素自動成為容器成員,稱為 Flex 專案(flex item)。
容器預設存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸的開始位置(與邊框的交叉點)叫做main start,結束位置叫做main end;交叉軸的開始位置叫做cross start,結束位置叫做cross end。
專案(flex item)預設沿主軸排列。單個item佔據的主軸空間叫做main size,佔據的交叉軸空間叫做cross size。
container(容器)的屬性
flex-direction
屬性決定主軸的方向(即item的排列方向)
- row(預設值):主軸為水平方向,起點在左端。
- row-reverse:主軸為水平方向,起點在右端。
- column:主軸為垂直方向,起點在上沿。
- column-reverse:主軸為垂直方向,起點在下沿。
flex-wrap
預設情況下,專案(item)都排在一條線(又稱"軸線")上。flex-wrap屬性定義,如果一條軸線排不下,如何換行。
- nowrap(預設):不換行。
- wrap:換行,第一行在上方。
- wrap-reverse:換行,第一行在下方。
flex-flow
flex-flow
屬性是flex-direction
屬性和flex-wrap
屬性的簡寫形式,預設值為row nowrap
justify-content
justify-content
屬性定義了專案在主軸上的對齊方式。
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
複製程式碼
- flex-start(預設值):左對齊
- flex-end:右對齊
- center: 居中
- space-between:兩端對齊,專案之間的間隔都相等
- space-around:每個專案兩側的間隔相等。所以,專案之間的間隔比專案與邊框的間隔大一倍。
align-items
align-items
屬性定義專案在交叉軸上如何對齊。
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
複製程式碼
具體的對齊方式與交叉軸的方向有關,下面假設交叉軸從上到下。
- flex-start:交叉軸的起點對齊。
- flex-end:交叉軸的終點對齊。
- center:交叉軸的中點對齊。
- baseline: 專案的第一行文字的基線對齊。
- stretch(預設值):如果專案未設定高度或設為auto,將佔滿整個容器的高度。
align-content
align-content
屬性定義了多根軸線的對齊方式。如果專案只有一根軸線,該屬性不起作用
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
複製程式碼
- flex-start:元素位於容器的開頭。各行向彈性盒容器的起始位置堆疊。彈性盒容器中第一行的側軸起始邊界緊靠住該彈性盒容器的側軸起始邊界,之後的每一行都緊靠住前面一行。
- flex-end:元素位於容器的結尾。各行向彈性盒容器的結束位置堆疊。彈性盒容器中最後一行的側軸起結束界緊靠住該彈性盒容器的側軸結束邊界,之後的每一行都緊靠住前面一行。
- center:元素位於容器的中心。各行向彈性盒容器的中間位置堆疊。各行兩兩緊靠住同時在彈性盒容器中居中對齊,保持彈性盒容器的側軸起始內容邊界和第一行之間的距離與該容器的側軸結束內容邊界與第最後一行之間的距離相等。(如果剩下的空間是負數,則各行會向兩個方向溢位的相等距離。)
- space-between:元素位於各行之間留有空白的容器內。各行在彈性盒容器中平均分佈。如果剩餘的空間是負數或彈性盒容器中只有一行,該值等效於'flex-start'。在其它情況下,第一行的側軸起始邊界緊靠住彈性盒容器的側軸起始內容邊界,最後一行的側軸結束邊界緊靠住彈性盒容器的側軸結束內容邊界,剩餘的行則按一定方式在彈性盒視窗中排列,以保持兩兩之間的空間相等。
- space-around:元素位於各行之前、之間、之後都留有空白的容器內。各行在彈性盒容器中平均分佈,兩端保留子元素與子元素之間間距大小的一半。如果剩餘的空間是負數或彈性盒容器中只有一行,該值等效於'center'。在其它情況下,各行會按一定方式在彈性盒容器中排列,以保持兩兩之間的空間相等,同時第一行前面及最後一行後面的空間是其他空間的一半。
- stretch(預設值):元素被拉伸以適應容器。各行將會伸展以佔用剩餘的空間。如果剩餘的空間是負數,該值等效於'flex-start'。在其它情況下,剩餘空間被所有行平分,以擴大它們的側軸尺寸。
item(專案)的屬性
order
order
屬性定義專案的排列順序。數值越小,排列越靠前,預設為0。
flex-grow
flex-grow
屬性定義專案的放大比例,預設為0,即如果存在剩餘空間,也不放大
如果所有專案的flex-grow屬性都為1,則它們將等分剩餘空間(如果有的話)。如果一個專案的flex-grow屬性為2,其他專案都為1,則前者佔據的剩餘空間將比其他項多一倍。
flex-shrink
flex-shrink
屬性定義了專案的縮小比例,預設為1,即如果空間不足,該專案將縮小。
如果所有專案的flex-shrink屬性都為1,當空間不足時,都將等比例縮小。如果一個專案的flex-shrink屬性為0,其他專案都為1,則空間不足時,前者不縮小。負值對該屬性無效
flex-basis
flex-basis
屬性用於設定或檢索彈性盒伸縮基準值。定義了在分配多餘空間之前,專案佔據的主軸空間(main size)。瀏覽器根據這個屬性,計算主軸是否有多餘空間。它的預設值為auto,即專案的本來大小。
它可以設為一個長度單位或者一個百分比,規定靈活專案的初始長度。
div:nth-of-type(2) {
flex-basis: 80px;
}
複製程式碼
flex
flex
屬性是flex-grow
, flex-shrink
和 flex-basis
的簡寫,預設值為0 1 auto
。後兩個屬性可選。
該屬性有兩個快捷值:auto
(1 1 auto
) 和 none
(0 0 auto
)。
建議優先使用這個屬性,而不是單獨寫三個分離的屬性,因為瀏覽器會推算相關值。
align-self
align-self
屬性允許單個專案有與其他專案不一樣的對齊方式,可覆蓋align-items
屬性。預設值為auto
,表示繼承父元素的align-items
屬性,如果沒有父元素,則等同於stretch
。
該屬性可能取6個值,除了auto,其他都與align-items屬性完全一致。
- auto:預設值。元素繼承了它的父容器的 align-items 屬性。如果沒有父容器則為 "stretch"。
- stretch:元素被拉伸以適應容器。如果指定側軸大小的屬性值為'auto',則其值會使專案的邊距盒的尺寸儘可能接近所在行的尺寸,但同時會遵照'min/max-width/height'屬性的限制。
- center:元素位於容器的中心。彈性盒子元素在該行的側軸(縱軸)上居中放置。(如果該行的尺寸小於彈性盒子元素的尺寸,則會向兩個方向溢位相同的長度)。
- flex-start:元素位於容器的開頭。彈性盒子元素的側軸(縱軸)起始位置的邊界緊靠住該行的側軸起始邊界。
- flex-end:元素位於容器的結尾。彈性盒子元素的側軸(縱軸)起始位置的邊界緊靠住該行的側軸結束邊界。
- baseline:元素位於容器的基線上。如彈性盒子元素的行內軸與側軸為同一條,則該值與'flex-start'等效。其它情況下,該值將參與基線對齊。
佈局技巧
單列布局
常見的這兩種單列布局的特點都是定寬,水平居中的,設定width或max-width和margin:auto即可;
二列&三列布局
二列布局的特徵是側邊欄固定寬度,主欄自適應寬度。三列布局的特徵是左右兩側固定寬度,中間列自適應寬度。
1.float + margin
將兩個側邊欄分別向左向右浮動,通過設定中間的主欄的margin為它們留出空間,形成三列布局
.left{
float: left;
width: 200px;
}
.right{
float: right;
width: 200px;
}
.main{
margin-left: 220px; /*預留出定寬兩欄的空間*/
margin-right: 220px;
}
複製程式碼
只設定一個浮動即可得到兩列布局
2.position + margin
通過將兩個側邊欄的position設定為absolute,然後將左邊欄的left設定為0,右邊欄的right設定為0,主欄設定margin為邊欄留出空間,即可得到三列布局。
.left{
position: absolute;
left: 0;
width: 200px;
}
.right{
position: absolute;
right: 0;
width: 200px;
}
.main{
margin-left: 220px;
margin-right: 220px;
}
複製程式碼
同樣,將定位元素改為一個可以得到兩列布局。
聖盃佈局
- 三者都設定向左浮動。
- 設定main寬度為100%,設定兩側欄的寬度。
- 設定負邊距,left設定負左邊距為100%,right設定負左邊距為負的自身寬度。
- 設定main的padding值給左右兩個子皮膚留出空間。
- 設定兩個子皮膚為相對定位,左邊欄的left值為負的自身寬度,右邊欄的right值為負的自身寬度。
<div class="container">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>
複製程式碼
.main{
float: left;
width: 100%;
}
.left{
float: left;
width: 200px;
margin-left: -100%;
position: relative;
left: -200px;
}
.right{
float: left;
width: 300px;
margin-left: -300px;
position: relative;
right: -300px;
}
.container {
padding: 0 300px 0 200px;
}
複製程式碼
二列的實現方法:
如果是左邊帶有側欄的二列布局,則去掉right,不設定主皮膚的padding-right值。
雙飛翼佈局
雙飛翼佈局和聖盃佈局的思想有些相似,都利用了浮動和負邊距,但雙飛翼佈局在主欄外加了一層div並設定margin用來容納側欄,兩側欄的負邊距都是相對於外層div而言,main的margin值變化便不會影響兩個側欄,這樣就省略了將側欄拉到主欄那一行後進行的relative定位(因為雙飛翼佈局留白就在父元素的內容區,而聖盃佈局的留白在父元素內容區之外)。
<div class="wrapper">
<div class="main"></div>
</div>
<div class="left"></div>
<div class="right"></div>
複製程式碼
.wrapper {
float: left;
width: 100%;
}
.main {
margin: 0 300px 0 200px;
}
.left {
float: left;
width: 200px;
margin-left: -100%;
}
.right {
float: left;
width: 300px;
margin-left: -300px;
}
複製程式碼
- 聖盃採用的是padding,而雙飛翼採用的margin,解決了聖盃佈局main的最小寬度不能小於左側欄的缺點。 雙飛翼佈局不用設定相對佈局,以及對應的left和right值。簡單說起來就是“雙飛翼佈局比聖盃佈局多建立了一個div,但不用相對佈局了”。
- 如果引入相對佈局,可以實現三欄佈局的各種組合,例如對右側欄設定position: relative; left: 200px;,可以實現left+right+main的佈局。
二列的實現方法:
如果是左邊帶有側欄的二欄佈局,則去掉右側欄,不要設定main-wrap的margin-right值,其他操作相同。反之亦然。
flex佈局
Flex 是 Flexible Box 的縮寫,意為“彈性佈局”,用來為盒狀模型提供最大的靈活性。除了在PC端相容性較差,沒有太大的缺陷,多用於移動端佈局。
.layout {
display: flex;
}
.main {
flex: 1;
}
.aside {
width: 200px;
}
複製程式碼
常用居中方法
margin: auto;
這是大家很常見的居中方式,元素會佔據你所指定的寬度,然後剩餘的寬度會一分為二成為左右外邊距。不過問題是,當瀏覽器視窗比元素的寬度還要窄時,瀏覽器會顯示水平滾動條。
在這種情況下使用 max-width 替代 width 可以使瀏覽器更好地處理小視窗的情況。這點在移動裝置上顯得尤為重要~
調整視窗大小看一下兩者的區別吧 居中在佈局中很常見,我們假設DOM文件結構如下,子元素要在父元素中居中:
<div class="parent">
<div class="child"></div>
</div>
複製程式碼
水平居中
- 子元素為行內元素:對父元素設定text-align:center;
- 子元素為定寬塊狀元素: 設定左右margin值為auto;
- 子元素為不定寬塊狀元素: 設定子元素為display:inline,然後在父元素上設定text-align:center;
- 通用方案: flex佈局,對父元素設定display:flex;justify-content:center;
垂直居中
垂直居中對於子元素是單行內聯文字、多行內聯文字以及塊狀元素採用的方案是不同的。
- 父元素一定,子元素為單行內聯文字:設定父元素的height等於行高line-height
- 父元素一定,子元素為多行內聯文字:設定父元素的display:table-cell或inline-block,再設定vertical-align:middle;
- 塊狀元素:設定子元素position:absolute 並設定top、bottom為0,父元素要設定定位為static以外的值,margin:auto;
- 通用方案: flex佈局,給父元素設定{display:flex; align-items:center;}。