從今天開(kāi)始學(xué)習(xí)CSS Layout
ps: 十分可怕,寫了近2個(gè)月,后面的章節(jié)應(yīng)該會(huì)快一些。
主要跟著這本書學(xué)習(xí)Learn CSS Layout
1 Box positioning in CSS
CSS布局的核心就是把HTML的元素映射一些rectangular boxes,這些盒子又分布在x、y、z三個(gè)軸上,x,y方向上的位置是由positioning scheme定義的,在CSS 2.1中定義了三種:normal flow,floats,absolute positioning。
Positioning Scheme
-
normal flow:包括三種fomatting context,block, inline, relativeformatting context。 -
floats:以自己的方式和normal flow進(jìn)行交互,并形成了大多數(shù)現(xiàn)代CSS grid框架。 -
absolute positioning:作用是相對(duì)于normal flow的絕對(duì)位置和固定的元素。
涉及這些的CSS的屬性是display,position,float。float和absolute定位可以看做是和normal flow的交互,也比較復(fù)雜,所以首先了解normal flow。從設(shè)計(jì)角度layout主要做了兩件事:
- 元素盒子的尺寸和對(duì)齊是如何處理的,這些一般是通過(guò)display的屬性(width,height,margin)來(lái)完成的
- 有相同父元素的的子元素是如何相互定位的
這章主要討論第二件事。
標(biāo)準(zhǔn)是這樣定義formatting context,即塊級(jí)元素就在一個(gè)block formatting context,行級(jí)元素就在inline formatting context。
Boxes in the normal flow belong to a formatting context, which may be block or inline, but not both simultaneously. Block-level boxes participate in a block formatting context. Inline-level boxes participate in an inline formatting context.
從視覺(jué)上看block formatting context就是一個(gè)垂直的棧布局,inline formatting context就是一個(gè)水平的棧布局。
Anonymous box generation
當(dāng)一個(gè)父級(jí)元素同時(shí)包含inline和block元素時(shí),會(huì)進(jìn)行Anonymous box的生成,具體規(guī)則是:
- 當(dāng)同時(shí)有inline和block元素存在時(shí),會(huì)生成
Anonymous block boxes,并將inline元素放進(jìn)去。 - 當(dāng)有inline元素且這個(gè)元素被text包裹時(shí),會(huì)生成
Anonymous inline boxes,并將text放進(jìn)去。
需要注意的是,這些Anonymous box是不會(huì)再chrome等瀏覽器的布局中顯示的,參考這個(gè)問(wèn)題。
Normal flow positioning
block formatting
block formatting 規(guī)則比較簡(jiǎn)單,如圖它遵循這樣一些規(guī)則

- 每個(gè)block box在父盒子的左外邊緣
- float不會(huì)影響左外邊緣的位置,但會(huì)影響文字的位置
- 沒(méi)有設(shè)置寬度的block box會(huì)填充滿整個(gè)父盒子的寬度
- 設(shè)置了寬度的會(huì)從左邊開(kāi)始計(jì)算
- 寬度即使沒(méi)有充滿父盒子,block box也不會(huì)同一行
inline formatting
inline formatting 就比較復(fù)雜了,因?yàn)樗婕暗綄?nèi)容分割成line box(將那些在一行的boxes的長(zhǎng)方形區(qū)域稱為line box),正常來(lái)說(shuō)inline的元素時(shí)在一行中平行布局,當(dāng)一行放不下時(shí)(這里的行寬度由它的父元素決定)會(huì)進(jìn)行垂直布局,此時(shí)是以line box為單位垂直布局。
inline box的另一個(gè)特點(diǎn)是給它設(shè)置width、height這些屬性時(shí)會(huì)被忽略,通常情況下inline元素的寬度由它的父元素決定。當(dāng)通過(guò)設(shè)置position:absolute使它成為block時(shí)才會(huì)使這些屬性生效。
對(duì)于line box,它的高度可以由line-height控制,以絕對(duì)高度或者相對(duì)高度的形式,絕對(duì)高度就是一個(gè)固定的值,或者以倍數(shù)于當(dāng)前元素設(shè)置的字體尺寸來(lái)決定,可大可小,默認(rèn)情況下根據(jù)字體的尺寸來(lái)決定行高。line box的高度是在計(jì)算所有inline box之后進(jìn)行的,然后設(shè)置除過(guò)vertical-align:top/bottom之外的其它vertical-align屬性。例子。
當(dāng)container有width時(shí),inline的布局像是block元素,實(shí)際上只是因?yàn)閣idth太小,導(dǎo)致每一個(gè)inline元素變成了上一段說(shuō)的line box。
vertical-align屬性
直觀了解vertical-align在和誰(shuí)對(duì)齊
垂直居中是一個(gè)常見(jiàn)的需求,這個(gè)例子通過(guò)將需要垂直居中的元素設(shè)為display:inline-box,vertical-align:middle解決了水平方向居中的問(wèn)題,配合一個(gè)container后面的樣式為height:100%的偽元素將line box的高度和container一致,這樣該元素就可以和這個(gè)偽元素對(duì)齊,解決了垂直方向居中的問(wèn)題。
display:inline和display:inline-box的區(qū)別可以見(jiàn)這個(gè)問(wèn)題。簡(jiǎn)單說(shuō)就是inline-box可以設(shè)置width和height,但又不會(huì)像block一樣獨(dú)占一行。
這個(gè)例子介紹了當(dāng)兩個(gè)元素中間存在空格時(shí)會(huì)生成一個(gè)匿名的inline box導(dǎo)致兩個(gè)本該在一行的inline box分別在兩行。
有幾種辦法可以解決:
- 手動(dòng)去掉那個(gè)空格,但這樣做會(huì)影響代碼可讀性
- 將父盒子的
font-size:0,再單獨(dú)給兩個(gè)子元素設(shè)置font-size,這可以使那個(gè)空格不再占用任何空間 - 父盒子設(shè)置
white-space: nowrap,雖然兩個(gè)子元素在一行了,但是空格依舊存在 - CSS3的
text-space-collapse屬性,缺點(diǎn)是目前許多瀏覽器暫不支持
不那么直觀的vertical-align:middle
middle的值不像baseline、top、bottom那么直觀,由定義它是將盒子(子盒子,一般是inline)的垂直中點(diǎn)和父盒子的baseline+x-height的一半對(duì)齊。
-
父盒子的baseline:這里的父盒子不是指包含它的container,而是它所在的line box。這個(gè)例子,可以看到parent是有固定高度60px的,但是"<"卻沒(méi)有那么高 -
x-height:就是指'x'字符的高度,這個(gè)例子表明line box的高度也不影響布局。
Normal flow: relative positioning
position:relative依舊算在文檔流中,然后根據(jù)top/left/bottom/right等屬性進(jìn)行位置的offset。
這個(gè)例子可以看出,4個(gè)div區(qū)域,沒(méi)有任何樣式的情況下是每個(gè)div垂直布局的,第一個(gè)div增加float之后跳出文檔流;第二個(gè)div加了10px的padding-top,增加了自己的高度;第三個(gè)div將position設(shè)置為relative,然后向上移動(dòng)了20px,向右移動(dòng)了10px,width成為原來(lái)的30%,這里注意,向上移動(dòng)是通過(guò)-20px完成的,而向右移動(dòng)又是通過(guò)10px完成的,兩個(gè)方向的正負(fù)數(shù)值代表的含義并不相同;第四個(gè)div只減少了寬度,但是它的位置并沒(méi)有隨著第三個(gè)div位置的變化而變化。
float position scheme
float布局本意是將文字環(huán)繞在圖片周圍,但現(xiàn)在已經(jīng)成為CSS里grid布局的基礎(chǔ)。
float將塊級(jí)元素從布局的文檔流中取出來(lái),這不會(huì)影響那些塊級(jí)盒子但是會(huì)影響line boxes。標(biāo)準(zhǔn)的描述說(shuō)"float是一個(gè)在當(dāng)前行上向左或向右移動(dòng)的盒子,最有趣的特性是內(nèi)容可以沿著一側(cè)流動(dòng)(flow along its side)。"
float有這些特殊的行為:
- float 跳出文檔流,因此它不會(huì)影響塊級(jí)元素的垂直布局
- float 和容器的左或者右外邊緣對(duì)齊
- float 從左邊或者右邊堆疊,當(dāng)有兩個(gè)right-float元素時(shí),第一個(gè)在容器的右外邊緣,第二個(gè)在第一個(gè)的左邊
- float 會(huì)影響當(dāng)前和隨后的inline元素,所有當(dāng)前和隨后的line boxes都需要縮短以給float留出空間
- float 不在文檔流中,所以它通常不會(huì)影響父元素的高度,這也是為什么開(kāi)發(fā)"clearfix"技術(shù)的原因之一
- float 可以使用clear屬性清除
下面逐條解釋這些特性:
浮動(dòng)的框向左或向右移動(dòng),直到它的外邊緣接觸父容器的的邊緣或者另一個(gè)浮動(dòng)框。如果存在line box則浮動(dòng)框的頂部與當(dāng)前l(fā)ine box的頂部對(duì)齊。以左浮動(dòng)為例,如果在一個(gè)左浮動(dòng)盒子生成時(shí)已經(jīng)有其他的左浮動(dòng)盒子存在,對(duì)每一個(gè)生成的左浮動(dòng)盒子來(lái)說(shuō)要么它的左邊框在已生成的盒子的右邊框右邊,要么top屬性小于已生成盒子的bottom,右浮動(dòng)同理。
如果水平空間不夠,float會(huì)向下移動(dòng)直到空間足夠或者沒(méi)有更多的float出現(xiàn)。因?yàn)閒loat不在文檔流中,所以浮動(dòng)框之前或之后創(chuàng)建的未定位框垂直流動(dòng),就像浮動(dòng)不存在。例子里就是三個(gè)div區(qū)域正常垂直布局。但是當(dāng)前和隨后的line box就需要縮短寬度為float留出區(qū)域,例子中就是綠色和橙色div區(qū)域中的文本組成的line box移動(dòng)了float區(qū)域中文本的寬度以便為它留出空間。
float不會(huì)影響文檔流中用于建立新塊級(jí)上下文元素內(nèi)的line box,對(duì)應(yīng)例子中綠色區(qū)域的文本組成的line box,這些元素要么放在float的側(cè)面或者任何前面float的下面。
clear屬性比較好理解,就是去除左邊或右邊的浮動(dòng)元素,默認(rèn)不去除,橙色區(qū)域清除了左邊的浮動(dòng)元素,無(wú)色區(qū)域去除了兩邊的浮動(dòng)元素。
float的另一個(gè)需要關(guān)注的特性是父元素高度的計(jì)算不考慮浮動(dòng)元素,也就是說(shuō)當(dāng)父容器只有float元素時(shí),它的高度為0。原因是在計(jì)算塊級(jí)元素高度時(shí)需要考慮一個(gè)屬性overflow,它的默認(rèn)值為visible,這種情況下不考慮float元素,當(dāng)你將他設(shè)置為其它值時(shí)就會(huì)將那些float元素計(jì)算在內(nèi)了。
claerfix技術(shù)是對(duì)基本浮動(dòng)清除的增強(qiáng),case 6想把將三組float元素塞進(jìn)他們對(duì)應(yīng)的父容器中,以目前的知識(shí)有三種做法:
- 在父元素的兩個(gè)float元素之后增加一個(gè)
clear:both的元素,也就是例子中的.hide。 - 在父元素后增加一個(gè)具有
clear:both的偽元素,也就是例子中的.clearfix:after。 - 改變父元素的
overflow屬性的值
這三個(gè)方法一般使用后兩個(gè)方法,這其中又比較推薦偽元素方法,這個(gè)例子體現(xiàn)了偽元素方法的優(yōu)勢(shì),如果是修改overflow屬性值,會(huì)將溢出內(nèi)容可滾動(dòng)而不是可見(jiàn)。
Absolute / fixed positioning scheme
Absolute / fixed 定位是比較簡(jiǎn)單直觀的一種模式,boxes相對(duì)于它的父容器以絕對(duì)偏移量定位。文檔流計(jì)算定位的時(shí)候會(huì)忽略絕對(duì)定位,同時(shí)絕對(duì)定位也不與它的兄弟元素交互,絕對(duì)定位元素中的float元素只與絕對(duì)定位元素中的其它元素交互。這兩種定位模式都與width,height,top,left,bottom,right屬性有關(guān)系,如果這些屬性都明確定義了,計(jì)算結(jié)果是非常直觀的,但只是部分指定,計(jì)算過(guò)程就復(fù)雜很多。
- fix定位與viewport有關(guān)
- absolute定位與父元素有關(guān)