1.定位
定位的概念就是它允許你定義一個元素相對於其他正常元素的位置,它應該出現在哪里,這里的其他元素可以是父元素,另一個元素甚至是瀏覽器窗口本身。還有就是浮動了,其實浮動並不完全算是定位,它的特性非常的神奇,以至於它在布局中被人廣泛的應用。我們會在后文中專門提及它的。
談及定位,我們就得從position屬性說起。你能准確的說出position的屬性值嗎?相信你可以完美地說出這么六個屬性值:static、relative、absolute、fixed、sticky和inherit。
- static(默認):元素框正常生成。塊級元素生成一個矩形框,作為文檔流的一部分;行內元素則會創建一個或多個行框,置於其父元素中。
- relative:元素框相對於之前正常文檔流中的位置發生偏移,並且原先的位置仍然被占據。發生偏移的時候,可能會覆蓋其他元素。
- absolute:元素框不再占有文檔流位置,並且相對於包含塊進行偏移(所謂的包含塊就是最近一級外層元素position不為static的元素)
- fixed:元素框不再占有文檔流位置,並且相對於視窗進行定位
- sticky:(這是css3新增的屬性值)粘性定位,官方的介紹比較簡單,或許你不能理解。其實,它就相當於relative和fixed混合。最初會被當作是relative,相對於原來的位置進行偏移;一旦超過一定閾值之后,會被當成fixed定位,相對於視口進行定位。
簡單地,介紹一下position的屬性值的含義后,在來看一下偏移量top、right、bottom、left四個屬性。
不清楚,當初在初學css的時候,會不會與margin這個屬性混淆?其實,它們之間是很容易去辨識地。因為這四個屬性值,其實是,定位時的偏移量。偏移量不會對static的元素起到作用。而margin,相對應的是盒子模型的外邊距,它會對每個元素框起到作用,使得元素框與其他元素之間產生空白。
下面:我們來看一下一些常用定位的偏移
- relative:它的偏移是相對於原先在文檔流中的位置
- absolute:它的偏移量是相對於最近一級position不是static的祖先元素的
- fixed:它的偏移量是相對於視口的。
其實,這里說描述的內容,應該都是需要理解的。這些相對於布局來說是基礎的,同時也是非常重要的。需要注意的是,這里的偏移量其實已經涉及到了接下來要說的尺寸。在做自適應布局設計時,往往希望這些偏移量的單位能夠使用百分比,或者相對的單位例如rem等。
2.尺寸
那之前上面談到過尺寸的單位——百分比。那么,下面部分我們就圍繞着尺寸單位展開。
尺寸,我們就應該從單位聊起,對於px這個單位,做網頁的應該在熟悉不過了,因此不多做介紹。
那么,我們可以來介紹一下下面幾個單位:
- 百分比:百分比的參照物是父元素,50%相當於父元素width的50%
- rem:這個對於復雜的設計圖相當有用,它是html的font-size的大小
- em:它雖然也是一個相對的單位,相對於父元素的font-size,但是,並不常用,主要是計算太麻煩了。
單位只是一個來定義元素大小的相應參考。另一個概念,或許可以用房子來打一個比方,在早年每幢房子都會在房子的外圍建一層柵欄,使得整一塊地區可以看成房子+內部地塊+柵欄+外圍地塊的模型。而在css中,每個元素也會有盒子模型的概念。
盒子模型:每個元素,都會形成一個矩形塊,主要包括四部分:margin(外邊距)+border(邊框)+padding(內邊距)+content(內容)
css中存在兩種不同的盒子模型,可以通過box-sizing設置不同的模型。兩種盒子模型,主要是width的寬度不同
這是標准盒子模型,可以看到width的長度等於content的寬度;而當將box-sizing的屬性值設置成border-box時,盒子模型的width=border+padding+content的總和。
可以看出,對於不同的模型的寬度是不同的。寬度默認的屬性值是auto,這個屬性值會使得內部元素的長度自動填充滿父元素的width。
但是,height的屬性值也是默認的auto,為什么沒有像width一樣呢?
其實,auto這個屬性值表示的是瀏覽器自動計算。這種自動計算,需要一個基准,一般瀏覽器都是允許高度滾動的,所以,會導致一個問題——瀏覽器找不到垂直方向上的基准。
同樣地道理也會被應用在margin屬性上。相信如果考察居中時,水平居中你可能閉着眼睛都能寫出來,但是垂直居中卻繞着腦袋想。這是因為如果是塊級元素水平居中只要將水平方向上的margin設置成auto就可以了。但是,垂直方向上卻沒有這么簡單,因為你設置成auto時,margin為0。這個問題,還是需要仔細思考一下的。
到此為止,布局最基本的部分我們已經將去大半,還有就是一塊浮動。
3.浮動
浮動,這是一個非常有意思的東西,在布局中被廣泛的應用。最初,設計浮動時,其實並不是為了布局的,而是為了實現文字環繞的特效
但是,浮動並不是僅僅這樣而已。何為浮動?浮動應該說是‘自成一派’,類似於ps中的圖層一樣,浮動的元素會在浮動層上面進行排布,而在原先文檔流中的元素位置,會被以某種方式進行刪除,但是還是會影響布局。你可能會覺得有疑問,什么叫影響布局?我們可以來舉個例子:
可以,發現雖然left塊因為左浮動,而使得原先元素在文檔流中占有的位置被刪除,但是,當right塊補上原先的位置時,right塊中的字體卻被擠出來了。這就是所謂的影響布局。
浮動為什么會被使用在布局中呢?因為設置浮動后的元素會形成BFC(使得內部的元素不會被外部所干擾),並且元素的寬度也不再自適應父元素寬度,而是適應自身內容。這樣就可以,輕松地實現多欄布局的效果。
浮動的內容還需要介紹一塊——清除浮動。可以看到,浮動元素,其實對於布局來說,是特別危險的。因為你可能這一塊做過浮動,但未做清除,那么造成高度塌陷的問題。就是上面圖示的那種情況。
清除浮動,最常用的方法有兩種:
- overflow: 將父元素的overflow,設置成hidden。
- after偽類:對子元素的after偽類進行設置。
這里只是稍微的提上一嘴。下面我們正式來介紹一下網頁的布局,本篇最核心的東西。
4.最初的布局——table
最初的時候,網頁簡單到可能只有文字和鏈接。這時候,大家最常用的就是table。因為table可以展示出多個塊的排布。
這種布局現在應該不常用了,因為在形色單一時,使用起來方便。但是,現在的網頁變得越來越復雜,適配的問題也是越來越多,這種布局已經不再時候了。
主要是div塊的出現,可以使得網頁進行靈活的排布,使得網頁變得繁榮。這時,開發者也開始思索如何去更加清晰地分辨網頁的層次。接下來,我們可以看看有哪些比較出名的布局方式。
5.兩欄布局
是否記得,那些一邊主體內容,一邊目錄的網頁,如圖:
類似於上圖的布局,可以定義為兩欄布局。
兩欄布局:一欄定寬,一欄自適應。這樣子做的好處是定寬的那一欄可以做廣告,自適應的可以作為內容主體。
實現的方式:
- float + margin:
<body> <div class="left">定寬</div> <div class="right">自適應</div> </body> .left{ width: 200px; height: 600px; background: red; float: left; display: table; text-align: center; line-height: 600px; color: #fff; } .right{ margin-left: 210px; height: 600px; background: yellow; text-align: center; line-height: 600px; }
其他的方法:還可以使用position的absolute,可以使用同樣的效果
6.三欄布局
三欄布局,也是經常會被使用到的一種布局。
它的特點:兩邊定寬,然后中間的width是auto的,可以自適應內容,再加上margin邊距,來進行設定。
三欄布局可以有4種實現方式,每種實現方式都有各自的優缺點。
1.使用左右兩欄使用float屬性,中間欄使用margin屬性進行撐開,注意的是html的結果
<div class="left">左欄</div> <div class="right">右欄</div> <div class="middle">中間欄</div> .left{ width: 200px;height: 300px; background: yellow; float: left; } .right{ width: 150px; height: 300px; background: green; float: right; } .middle{ height: 300px; background: red; margin-left: 220px; margin-right: 160px; }
缺點是:1. 當寬度小於左右兩邊寬度之和時,右側欄會被擠下去;2. html的結構不正確
2. 使用position定位實現,即左右兩欄使用position進行定位,中間欄使用margin進行定位
<div class="left">左欄</div> <div class="middle">中間欄</div> <div class="right">右欄</div> .left{ background: yellow; width: 200px; height: 300px; position: absolute; top: 0; left: 0; } .middle{ height: 300px; margin: 0 220px; background: red; } .right{ height: 300px; width: 200px; position: absolute; top: 0; right: 0; background: green; }
好處是:html結構正常。
缺點時:當父元素有內外邊距時,會導致中間欄的位置出現偏差
3. 使用float和BFC配合聖杯布局
將middle的寬度設置為100%,然后將其float設置為left,其中的main塊設置margin屬性,然后左邊欄設置float為left,之后設置margin為-100%,右欄也設置為float:left,之后margin-left為自身大小。
<div class="wrapper"> <div class="middle"> <div class="main">中間</div> </div> <div class="left"> 左欄 </div> <div class="right"> 右欄 </div> </div> .wrapper{ overflow: hidden; //清除浮動 } .middle{ width: 100%; float: left; } .middle .main{ margin: 0 220px; background: red; } .left{ width: 200px; height: 300px; float: left; background: green; margin-left: -100%; } .right{ width: 200px; height: 300px; float: left; background: yellow; margin-left: -200px; }
7.彈性布局(flex)
彈性盒子(Flexbox)布局是一種為一維布局而設計的布局方法。一維的意思是你希望內容是按行或者列來布局。你可以使用display: flex
來將元素變為彈性布局。
.container { display: flex; }
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div>
該容器的直接子元素會變為彈性項(flex item),並按行排列。
如圖:
7.1. 彈性盒子的軸(axes)
在上面的例子中,我們會稱彈性項在行內是從起始位置開始排列,而不是說它們是左對齊。這些元素會按行排列是因為默認的flex-direction
值為row
,row
代表了文本的行文方向。由於我們工作的環境是英文(中文也是如此),一種自左向右的語言,行的開始位置就是在左邊,因此我們的彈性項也是從左邊開始的。因此flex-direction
的值被定義為彈性盒子的主軸(main axis)。
交叉軸(cross axis)則是和主軸垂直的一條軸。如果你的flex-direction
是row
並且彈性項是按照行內方向排列的,那么交叉軸就是塊級元素的排列方向。如果flex-direction
是column
那么彈性項就會以塊級元素排列的方向排布,然后交叉軸就會變為row
。
如果你習慣於從主軸與交叉軸的角度來使用彈性盒子,那么一切會變得非常簡單。
7.2. 方向和次序
彈性盒子模型讓我們可以通過為flex-direction
屬性設置row-reverse
或column-reverse
值來改變主軸上彈性項的方向。
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div>
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { width: 500px; border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: flex; flex-direction: row-reverse; } .item { width: 100px; height: 100px; padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); }
7.3. 一些Flex的屬性
這些flex的屬性是用來控制彈性項在主軸上空間大小的。這三個屬性是:
- flex-grow
- flex-shrink
- flex-basis
通常可以使用它們的簡寫形式:flex
。第一個值代表flex-grow
,第二個是flex-shrink
,而第三個則是flex-basis
。
.item { flex: 1 1 200px; }
flex-basis
會為彈性項設置未拉伸和壓縮時的初始大小。在上面的例子中,大小是200px,因此我們會給每個項200px的空間大小。但是大多數情況下容器元素大小不會正好被分為許多200px大小的項,而是可能有一些不足或剩余空間。flex-grow
和flow-shrink
屬性允許我們在容器大小不足或有空余時控制各個彈性項的大小。
如果flex-grow
的值是任意的正數,那么彈性項會被允許拉伸來占據更多的空間。因此,在上面的例子中,當各項被設為200px后,所有多余的空間會被每個彈性項平分並填滿。
如果flex-shrink
的值為任意的正數,那么當彈性項被設置了flex-basis
后,元素溢出容器時會進行收縮。在上面這個CSS的例子中,如果容器空間不足,每個彈性項會等比例縮放以適應容器的大小。
flex-grow
和flex-shrink
的值可以是任意的正數。一個具有較大flex-grow
值的彈性項會在容器有剩余空間時拉伸更大的比例;而一個具有更大flex-shrink
值的項則會在容器空間不足時被壓縮的更多。
1 <div class="container"> 2 <div class="item">1</div> 3 <div class="item">2</div> 4 <div class="item">3</div> 5 </div>
1 body { 2 padding: 20px; 3 font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; 4 } 5 6 * {box-sizing: border-box;} 7 8 p { 9 margin: 0 0 1em 0; 10 } 11 12 .container { 13 width: 500px; 14 border: 5px solid rgb(111,41,97); 15 border-radius: .5em; 16 padding: 10px; 17 display: flex; 18 } 19 20 .item { 21 flex: 1 1 0; 22 width: 100px; 23 height: 100px; 24 padding: 10px; 25 background-color: rgba(111,41,97,.3); 26 border: 2px solid rgba(111,41,97,.5); 27 } 28 29 .container :first-child { 30 flex: 2 1 0; 31 }
8. 網格布局(grid layout)
CSS網格布局(grid layout)是一種用來進行二維布局的技術。二維(two-dimesional)意味着你希望按照行和列來排布你的內容。和彈性盒子類似,網格布局也需要設置一個display
值。你可以為容器元素設置display: grid
,並且使用grid-template-columns
和grid-template-rows
屬性來控制網格中的行與列。
.container { display: grid; grid-template-columns: 200px 200px 200px; grid-template-rows: 200px 200px; }
上面這段CSS會創建一個行列元素大小固定的網格。不過這也許並不是你希望的。默認值為auto
,你可以認為這代表了“讓格子盡可能的大”。如果你每沒有指定行(row track)的大小,所有添加進來的行內容大小都會被置為auto
。一種常用的模式是為網格制定列寬度,但是允許網格按需添加行。
你可以使用任意的長度單位或時百分比來設置行與列,同時你可以使用為網格系統所創造的新的單位——fr
。fr
是一種彈性單位,它可以指定網格容器內的空間被如何划分。
網格會替你計算與分配空間,你不需要去計算元素的百分比去適應容器大小。在下面這個例子中,我們使用fr
來創建網格的列,這使得網格的列可以自適應。同時我們還使用了grid-gap
來保證元素間的間距(關於網格內元素與的間距會在“對齊”這一部分詳細介紹)。
<div class="container"> <div>1</div> <div>2</div> <div>3</div> <div>4</div> <div>5<br>has more content.</div> </div>
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { width: 500px; border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: grid; grid-template-columns: 1fr 1fr 1fr; grid-gap: 20px; } .container > div { padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); }