1. 前言
前端圈有個(gè)“梗”:在面試時(shí)分瘦,問個(gè)css的position屬性能刷掉一半人,其中不乏工作四五年的同學(xué)琉苇。在公司一直有參與前端的基礎(chǔ)面試嘲玫,深感這個(gè)“梗”不是個(gè)玩笑并扇。
然而去团,我覺得實(shí)際比例可能會(huì)更高,甚至很多面試官自己也未必真正掌握穷蛹。因?yàn)榇蟛糠智岸送瑢W(xué)土陪,可能不知道初始包含塊的概念,或知道但對(duì)這個(gè)概念理解有誤俩莽。
造成這種現(xiàn)象的原因主要有兩方面旺坠,一方面是在介紹這個(gè)知識(shí)點(diǎn)時(shí),網(wǎng)上有謬誤的文章太多扮超,國(guó)內(nèi)外亦如此(MDN也名列其中)取刃,導(dǎo)致很多同學(xué)被誤導(dǎo)(我一開始也是)蹋肮,而且這種錯(cuò)誤被代代相傳;另一方面可能是我們平時(shí)不太注重概念的定義璧疗、自身對(duì)待知識(shí)的態(tài)度還不夠嚴(yán)謹(jǐn)坯辩、缺乏驗(yàn)證精神和系統(tǒng)總結(jié)的習(xí)慣。
一次偶然的機(jī)會(huì)崩侠,我發(fā)現(xiàn)了這種謬誤漆魔,并找到了W3C組織對(duì)初始化包含塊的官方定義,也為了讓剛?cè)肭岸巳Φ耐瑢W(xué)少走一些彎路却音,在此我想借本文分享給大家(詳述請(qǐng)見5.5. 包含塊章節(jié))改抡,也系統(tǒng)分享一下,本人在前端布局基礎(chǔ)方面積累的淺薄經(jīng)驗(yàn)系瓢。(因?yàn)槭窍到y(tǒng)概述阿纤,所以篇幅會(huì)比較長(zhǎng),希望各位讀者有心理準(zhǔn)備)
2. 什么是前端布局基礎(chǔ)夷陋?
前端布局方案主要有三種:
傳統(tǒng)布局方案(借助浮動(dòng)欠拾、定位等手段)
flex布局方案
grid布局方案
這些方案都能夠解決布局問題,而且每個(gè)方案都有各自的理論基礎(chǔ)骗绕,那么哪一個(gè)方案的基礎(chǔ)理論可以稱得上是前端布局基礎(chǔ)藐窄?要回答這個(gè)問題,我們還得深入去了解這三種方案的特性酬土。
傳統(tǒng)布局方案荆忍,需要使用者熟練掌握元素的分類及布局特性、浮動(dòng)原理和定位原理等眾多基礎(chǔ)知識(shí)诺凡,方能在解決各類前端布局問題時(shí)游刃有余东揣,這不僅學(xué)習(xí)成本大践惑,而且實(shí)現(xiàn)的復(fù)雜度也高腹泌,實(shí)現(xiàn)的CSS代碼也不夠精簡(jiǎn)、優(yōu)雅尔觉。但由于其基礎(chǔ)知識(shí)來源于CSS2凉袱,所以瀏覽器兼容性最好,對(duì)于用戶是友好的侦铜。
flex布局方案专甩,正是為了解決傳統(tǒng)布局方案的種種不便,而提出的一種新型改進(jìn)方案钉稍,它不再需要借助浮動(dòng)和定位等布局手段,而是通過父元素(flex box)單方面配置相關(guān)的CSS屬性來決定子元素的布局規(guī)則,且在大多情況下無需子元素(flex item)參與耕拷,就能完成子元素間的布局問題,不僅學(xué)習(xí)成本低(公司之前有幾個(gè)后端工程師亦能快速上手)蒙袍,且大大簡(jiǎn)化了布局的實(shí)現(xiàn)復(fù)雜度,CSS代碼也更加精煉嫩挤。美中不足的是IE10才開始支持害幅,且需要使用-ms-前綴(IE11無需)。
雖然現(xiàn)今的手機(jī)多使用的是現(xiàn)代瀏覽器岂昭,對(duì)flex支持度較好以现,然而并不是每一款手機(jī)都如此:筆者曾在一個(gè)移動(dòng)端項(xiàng)目采用過flex布局方案,然而公司的測(cè)試同學(xué)在“華為榮耀5”的自帶瀏覽器约啊,檢測(cè)到無法支持flex布局邑遏,我們能夠跟測(cè)試的同學(xué)說,是這款華為手機(jī)的瀏覽器有問題嗎恰矩?顯然不能无宿。于是故筆者在項(xiàng)目早期就及時(shí)放棄了flex布局方案,改用傳統(tǒng)布局方案實(shí)現(xiàn)枢里,避免了后面大規(guī)模的改動(dòng)孽鸡。
grid布局方案,是由微軟提出栏豺,相對(duì)于傳統(tǒng)布局方案和flex布局方案彬碱,它是一種二維布局方案,在IE10開始支持奥洼,但需要使用-ms-后綴(IE11+不再需要)巷疼。
總的來說,這三類方案都能基本解決日常的前端布局問題灵奖,且從易用性嚼沿、靈活性和強(qiáng)大性來說,flex布局和grid布局更是未來的趨勢(shì)瓷患。但是從當(dāng)前各版本瀏覽器在用戶市場(chǎng)上的使用情況和各方案的瀏覽器兼容性來看骡尽,傳統(tǒng)布局方案對(duì)用戶最友好,具有一定的不可替代性擅编,所以我覺得攀细,傳統(tǒng)布局方案是最應(yīng)該先掌握好的,尤其是對(duì)于在to B企業(yè)工作的前端同學(xué)來說爱态。
所以本文將詳細(xì)介紹的“前端布局基礎(chǔ)”谭贪,指的是圍繞著“傳統(tǒng)布局方案”的眾多CSS知識(shí),其主要內(nèi)容來源于CSS2規(guī)范锦担。
3. 為什么要學(xué)好前端布局基礎(chǔ)俭识?
頁面寫多了的前端同學(xué),我想應(yīng)該都會(huì)有這樣一個(gè)深刻的感受:在編寫頁面時(shí)洞渔,經(jīng)常會(huì)遇到不同場(chǎng)景的布局問題套媚,我們不僅需要針對(duì)特定的場(chǎng)景選定可實(shí)現(xiàn)的布局實(shí)現(xiàn)方案理盆,而且需要考慮未來可能發(fā)生的變化。
而要做好這一點(diǎn)凑阶,就需要扎實(shí)的前端基礎(chǔ)作為依托猿规。
所以在我看來,學(xué)好前端布局基礎(chǔ)宙橱,其目的是為了在面對(duì)不同場(chǎng)景的布局問題時(shí)姨俩,能夠提出一種合理的布局方案:既能解決問題,又能最大程度地?fù)肀ё兓?/p>
4. 量化布局方案的合理性
前面提到過的“解決問題”师郑、“擁抱變化”环葵,僅僅是合理布局方案的兩大核心目標(biāo),如果想要讓目標(biāo)更好地落地宝冕,我們?nèi)孕枰恍┝炕侠硇缘脑瓌t张遭,來提升對(duì)目標(biāo)的方向感,以讓目標(biāo)變得更加可執(zhí)行地梨。
說到量化“解決問題”這個(gè)目標(biāo)菊卷,對(duì)于即寫即呈現(xiàn)的前端代碼來說,我們可以很直觀地判斷一種方案是否可行宝剖,所以不需要太多的量化手段洁闰,我們主要是要量化“擁抱變化”這個(gè)目標(biāo)。
要想量化“擁抱變化”這個(gè)目標(biāo)万细,我們首先得清楚“變化”有哪些扑眉。筆者根據(jù)過往的開發(fā)經(jīng)驗(yàn),將變化分為兩大類:一是布局需求的變化赖钞,二是運(yùn)行環(huán)境的變化腰素。
而針這這兩類變化,我提出如下量化原則:
一雪营、對(duì)于布局需求的變化弓千,可以做到:
方便快速定位需修改的位置
能夠不花或用最少的修改成本應(yīng)對(duì)變化
二、對(duì)于運(yùn)行環(huán)境的變化卓缰,可以做到:
- 在不同瀏覽器均有正確或良好的顯示
如果一個(gè)方案能夠體現(xiàn)以上幾點(diǎn)原則计呈,我認(rèn)為可以稱得上是一個(gè)合理的方案。最后征唬,我將布局實(shí)現(xiàn)方案的合理性歸納為:方案在滿足正確性的前提下,其實(shí)現(xiàn)邏輯規(guī)范茁彭、實(shí)現(xiàn)職責(zé)分明且擁有良好的瀏覽器兼容性总寒。
下面我們正式開始介紹與“傳統(tǒng)布局方案”相關(guān)的布局基礎(chǔ)知識(shí)。
5. 布局基礎(chǔ)要點(diǎn)
5.1. CSS標(biāo)準(zhǔn)盒模型(或W3C盒模型)
一個(gè)web頁面是由眾多html元素拼湊而成的理肺,而每一個(gè)html元素摄闸,都被解析為一個(gè)矩形盒善镰,而CSS盒模型就是這種矩形盒的解構(gòu)模型。CSS盒模型年枕,它由內(nèi)到外炫欺、被四條邊界Content edge、Padding edge熏兄、Border edge和Margin edge劃分為四個(gè)區(qū)域:Content area品洛、Padding area、Border area和Margin area摩桶,在形狀上桥状,Content area(又稱content-box)是實(shí)心矩形,其余是空心環(huán)形(空心部分是Content area)硝清,如下圖所示:
CSS盒模型-區(qū)域劃分圖
此外辅斟,每個(gè)區(qū)域都有其特定的作用:Content area,是當(dāng)前元素用來容納所有子孫元素芦拿;Padding area士飒,是當(dāng)前元素用來隔離自身和子孫元素;Border area是當(dāng)前元素用來顯示自身的輪廓蔗崎;Margin area变汪,是當(dāng)前元素用來隔離自身和相鄰元素。理解每個(gè)區(qū)域的作用和職責(zé)至關(guān)重要蚁趁,有助于我們寫出優(yōu)雅裙盾、清晰的布局代碼。
CSS盒模型-區(qū)域作用圖
而每個(gè)區(qū)域的尺寸他嫡,又分別由特定的CSS屬性來控制番官,如下圖所示:
CSS盒模型-屬性控制圖
這些CSS尺寸屬性(width、height钢属、padding徘熔、border和margin),相當(dāng)于一個(gè)個(gè)hook淆党,我們可以通過設(shè)置這些“hook”來達(dá)到調(diào)整元素尺寸的目的酷师。
5.2. box-sizing(CSS3屬性)
5.2.1. box-sizing的作用
box-sizing,顧名思義染乌,其作用與設(shè)置CSS box的尺寸大小有關(guān)山孔,而CSS box又可細(xì)分為:
content-box(即content area)
padding-box(=content area + padding area)
border-box(=content area + padding area + border area)
margin-box(=content area + padding area + border area + margin area)
簡(jiǎn)單來說,box-sizing的作用就是告訴瀏覽器:CSS屬性width和height是用于設(shè)置哪一種box的尺寸荷憋,在W3C標(biāo)準(zhǔn)中,box-sizing的值僅有content-box和border-box(firefox則額外支持padding-box)台颠。所以,
當(dāng)box-sizing的值為content-box(默認(rèn)值)時(shí)勒庄,有:
width = content-width;
height = content-height;
當(dāng)box-sizing的值為border-box時(shí)串前,有:
width = content-width + padding-left + padding-right + border-left-width + border-right-width;
height = content-height + padding-top + padding-bottom + border-top-height + border-bottom-height;
關(guān)于box-sizing的作用瘫里,還有另一種表述:告訴瀏覽器,是使用W3C盒模型荡碾,還是使用IE盒模型谨读。
5.2.2. box-sizing的瀏覽器兼容性
box-sizing是CSS3屬性,在IE8+(包含IE8)開始支持坛吁,然而在IE8劳殖,box-sizing的值為border-box時(shí),不能與min-width, max-width, min-height或max-height的一起使用阶冈,因?yàn)镮E8對(duì)min-和max-的解析闷尿,仍是作用于content-box,不受box-sizing屬性控制女坑。
**5.2.3. box-sizing的******產(chǎn)生原因
僅僅掌握box-sizing的基礎(chǔ)使用填具,是無法真正理解box-sizing的作用,所以要想把box-sizing用好匆骗,我們還得從CSS盒模型的發(fā)展史來深入理解box-sizing的產(chǎn)生原因劳景。
在CSS的發(fā)展歷程中,有兩個(gè)版本碉就,一個(gè)是IE盒模型盟广,另外一個(gè)是W3C盒模型。IE盒模型瓮钥,在IE5-(包含IE5)和navigator4上均有使用筋量;而W3C盒模型,在IE6+(包含IE6)標(biāo)準(zhǔn)模式開始得到支持碉熄。兩種版本的盒模型桨武,其實(shí)在模型結(jié)構(gòu)上是一致的,只是with和height屬性的計(jì)算規(guī)則不一樣锈津,其區(qū)別呀酸,等價(jià)于“box-sizing的兩個(gè)屬性值border-box和content-box的區(qū)別“,如下圖所示:
IE盒模型和W3C盒模型的區(qū)別
在了解了CSS盒模型的發(fā)展歷程琼梆,以及后來新增的box-sizing的開始支持時(shí)間性誉,我們不難發(fā)現(xiàn):
IE5-采用IE盒模型
IE6、7的標(biāo)準(zhǔn)模式放棄了IE盒模型茎杂,轉(zhuǎn)為使用W3C盒模型
IE8+借助box-sizing错览,又重新提供了對(duì)IE盒模型的支持
對(duì)于IE盒模型,我們看到了W3C組織先去后留的反復(fù)態(tài)度蛉顽,我不禁提出以下兩點(diǎn)疑惑:
問題一: 為什么W3C組織在制定盒模型標(biāo)準(zhǔn)時(shí)蝗砾,一開始會(huì)放棄IE盒模型,而重新建立以content-box為計(jì)算規(guī)則的W3C盒模型携冤?W3C盒模型比IE盒模型好在哪里悼粮?
問題二:為什么在CSS3中,又重新提供了對(duì)IE盒模型的支持(box-sizing設(shè)置為border-box)曾棕,又是基于哪方面的考慮扣猫?
關(guān)于第一個(gè)問題,本人并沒有找到相關(guān)的官方說明翘地,但我比較認(rèn)可的一種說法是:
在日常生活中申尤,我們?cè)诜艝|西時(shí),會(huì)關(guān)心東西放到多大的盒子里面衙耕,這里的“多大”昧穿,往往指的是盒子的容量,而不是整個(gè)盒子的尺寸橙喘。而HTML元素也被看成是一個(gè)盒子时鸵、一個(gè)容器,相應(yīng)地厅瞎,我們也會(huì)更關(guān)注其內(nèi)容區(qū)域的尺寸饰潜,也更希望對(duì)內(nèi)容區(qū)域有更強(qiáng)的控制力。所以和簸,從存儲(chǔ)的角度來看彭雾,W3C盒模型更符合這種認(rèn)知,借助width和height锁保,我們可以通過聲明的方式薯酝,直接設(shè)置conent-box的尺寸。而如果采用IE盒模型爽柒,我們只能先設(shè)置整個(gè)盒子的尺寸(border-box)吴菠,最后由瀏覽器自動(dòng)計(jì)算出content-box的尺寸,顯得對(duì)content-box尺寸的控制力較弱霉赡。
關(guān)于第二個(gè)問題橄务,我認(rèn)為有以下幾個(gè)原因:
1. 有助于復(fù)用基于IE盒模型開發(fā)的CSS代碼;
2. IE盒模型的“遺老遺少”可以延續(xù)計(jì)算習(xí)慣穴亏;
部分html元素蜂挪,在解析時(shí)依然采用IE盒模型的計(jì)算規(guī)則(這樣的元素有select、button)嗓化,使用IE盒模型有助于保持一致性棠涮;
從元素布局的角度來看,IE盒模型的width和height的語義更符合人類的直觀認(rèn)知(盒子的尺寸刺覆、輪廓應(yīng)該以border為界)严肪;
5. 在彈性布局和響應(yīng)式布局場(chǎng)景,IE盒模型比W3C盒模型表現(xiàn)更佳(更容易實(shí)現(xiàn)、瀏覽器兼容性更好)驳糯,如設(shè)置某個(gè)元素的寬度始終占當(dāng)前行總寬度的固定百分比(小于100%)篇梭,并且該元素?fù)碛泄潭ㄏ袼氐膒adding;
舉個(gè)例子:設(shè)置一個(gè)元素酝枢,其寬度分別為當(dāng)前行的40%恬偷,且該元素的padding固定為10px。
IE盒模型的實(shí)現(xiàn)方案:
方案一: 使用一個(gè)div即可實(shí)現(xiàn)帘睦,直接設(shè)置width為40%袍患,padding為10px;
W3C盒模型的實(shí)現(xiàn)方案:
方案一:使用兩個(gè)div模擬實(shí)現(xiàn)竣付,外層div的width設(shè)置為40%诡延,內(nèi)層div的padding為10px, width為auto;
方案二:使用一個(gè)div即可實(shí)現(xiàn)古胆,但是需要借用CSS3的calc函數(shù)肆良,動(dòng)態(tài)計(jì)算其內(nèi)容區(qū)域的寬度,即width為calc(40% - 20px), padding為10px赤兴;
顯然妖滔,IE盒模型的實(shí)現(xiàn)方案更加簡(jiǎn)潔,而且瀏覽器兼容性更好桶良。
對(duì)上述兩個(gè)問題的解答座舍,其實(shí)也是對(duì)IE盒模型和W3C盒模型的一個(gè)比較。我們可以從比較中陨帆,明晰兩種盒模型各自的優(yōu)缺點(diǎn)曲秉。同時(shí),經(jīng)過大量的實(shí)踐經(jīng)驗(yàn)證明和充分討論疲牵,IE盒模型總體上是優(yōu)于W3C盒模型承二,這也是IE盒模型能夠“王者歸來”,被W3C組織重新啟用的真正原因纲爸。
于是乎亥鸠,為了重新在新規(guī)范中支持IE盒模型,也為了向后兼容W3C盒模型识啦,W3C組織在CSS3中添加了box-sizing屬性负蚊,用于切換這兩種盒模型。
5.2.4. 對(duì)box-sizing的評(píng)價(jià)
在我看來颓哮,在CSS3中添加box-sizing其實(shí)是一種比較trick的彌補(bǔ)方式家妆。雖然這種設(shè)計(jì)能重新提供對(duì)IE盒模型的支持僧免,但是在某種程度上尊蚁,造成了CSS屬性width和height具有二義性喧伞,使其職責(zé)變得不單一建蹄。然而這似乎又是最可取的修正方案了枷餐,因?yàn)樵诰W(wǎng)上已經(jīng)存在了大量基于W3C盒模型開發(fā)的網(wǎng)頁上真,后續(xù)的修正方案不得不考慮向后兼容界拦。我們只能在不合理設(shè)計(jì)的基礎(chǔ)上轿腺,再次用不優(yōu)雅的設(shè)計(jì)來解決新的問題。
如果能夠穿越時(shí)空齿税,回到W3C組織在討論“如何設(shè)計(jì)標(biāo)準(zhǔn)盒模型”時(shí)彼硫,我認(rèn)為更合適的設(shè)計(jì)方案是添加新的屬性單獨(dú)用于設(shè)置content-box的尺寸炊豪,而保留IE盒模型width和height原來的語義凌箕。這樣就不會(huì)有后來的box-sizing屬性。
我猜想W3C組織也想過這種方案词渤,但是當(dāng)時(shí)可能認(rèn)為:
1. 直接設(shè)置元素border-box尺寸的意義不大牵舱,且border-box的尺寸設(shè)置也能夠通過設(shè)置content-box的尺寸來實(shí)現(xiàn);(其實(shí)同時(shí)兩種支持content-box和border-box尺寸的設(shè)置也無妨缺虐,完全可以當(dāng)做是語法糖)
2. 設(shè)置content-box尺寸又屬于高頻操作芜壁,若新增的屬性命名為content-width或content-height則顯得名稱太長(zhǎng);(命名為cwidth和cheight也行)
基于這兩點(diǎn)高氮,最終提出了用width和height來設(shè)置content-box尺寸的解決方案慧妄,也就是如今我們看到的W3C盒模型。
縱觀CSS盒模型的發(fā)展史和box-sizing的創(chuàng)建原因剪芍,感觸比較深的就是:不合理的設(shè)計(jì)并不是總會(huì)被修正塞淹,因?yàn)榧扔袑?shí)現(xiàn)的廣泛應(yīng)用,會(huì)使得其被繼續(xù)遵循罪裹。而后續(xù)的新增設(shè)計(jì)饱普,也是建立在先前不合理設(shè)計(jì)的基礎(chǔ)上。這是否也驗(yàn)證了黑格爾的哲學(xué)名言:存在即合理状共?
關(guān)于對(duì)box-sizing的評(píng)價(jià)和思考套耕,可能顯得有一些馬后炮,一些猜想也可能只是筆者的憑空臆想峡继,并非W3C組織原意冯袍。在這里只是為了分享我對(duì)重構(gòu)的一些思考,也是為了與和我有同樣疑惑的同學(xué)做個(gè)交流碾牌。
5.2.5. box-sizing的最佳實(shí)踐
在這里主要回答三個(gè)問題:
問題一:box-sizing的值康愤,取content-box好,還是取border-box值好小染?
如果最低需要兼容IE6翘瓮、7,那么box-sizing不可使用裤翩,只能使用W3C盒模型资盅;
如果最低只需兼容IE8调榄,那么使用content-box在功能上完全沒有問題,只是在一些彈性布局和響應(yīng)式布局實(shí)現(xiàn)上呵扛,會(huì)稍微麻煩一點(diǎn)每庆;而border-box雖然在這些方面表現(xiàn)更好,但是不能和IE8的min-width今穿、min-height缤灵、max-width和max-height四個(gè)屬性一同使用,使用的話就要稍微注意一下蓝晒;
如果最低只需兼容IE9腮出,那么本人覺得,全局配置取content-box更為合適芝薇,局部配置二者均可胚嘲。原因如下:
CSS3提供了calc函數(shù)(IE9+),使得W3C盒模型有了強(qiáng)有力的助攻洛二,在彈性布局和響應(yīng)式布局的表現(xiàn)馋劈,與IE盒模型無異;
默認(rèn)優(yōu)于配置原則:我個(gè)人認(rèn)為晾嘶,“默認(rèn)優(yōu)于配置”妓雾,特別是在reset.css這種架構(gòu)級(jí)、平臺(tái)級(jí)的配置文件垒迂,要盡量避免對(duì)未來可能引入的模塊有侵入性械姻。譬如,我們?cè)谝粋€(gè)項(xiàng)目中時(shí)常需要引入第三方組件娇斑,如果這個(gè)組件沒有強(qiáng)聲明box-sizing,那么其默認(rèn)使用的就是W3C標(biāo)準(zhǔn)盒模型策添,如果在全局的reset.css中設(shè)置box-sizing的值為border-box以選用IE盒模型,那么就會(huì)影響到這一類默認(rèn)基于W3C盒模型的第三方組件的樣式毫缆。這里也給我們提了一個(gè)醒唯竹,在封裝組件時(shí),記得強(qiáng)聲明box-sizing苦丁,哪怕你使用默認(rèn)的content-box浸颓。
總之,大部分場(chǎng)景二者可以互換旺拉,只是使用理念不一樣产上。小部分場(chǎng)景border-box更具優(yōu)勢(shì),但隨著calc函數(shù)的支持蛾狗,這種優(yōu)勢(shì)已經(jīng)不再晋涣,相反content-box是默認(rèn)值的優(yōu)勢(shì)愈加明顯。
我個(gè)人建議是:全局使用默認(rèn)W3C盒模型(你的CSS代碼最低能夠兼容IE6/7沉桌,在IE8也可以和min-和max-一起使用)谢鹊,局部場(chǎng)景二者均可(僅把IE盒模型當(dāng)作是一種布局技巧來使用)算吩。你喜歡全局使用IE盒模型也是可以的,只要確認(rèn)項(xiàng)目只需要兼容到IE8佃扼,即便有可能影響到引入的第三方組件偎巢,也是有辦法處理的。
問題二:如果想要全局使用IE盒模型兼耀,那么在reset.css中压昼,該怎樣設(shè)置box-sizing?
這里提供一個(gè)參考:
html {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
*, *:before, *:after {
-webkit-box-sizing: inherit;
-moz-box-sizing: inherit;
box-sizing: inherit;
}
這樣設(shè)置的好處有:
1. 子元素的盒模型類型瘤运,默認(rèn)由父元素決定窍霞,方便組件統(tǒng)一設(shè)置;
2. 支持低版本的瀏覽器:Safari (< 5.1), Chrome (< 10), and Firefox (< 29);
問題三:Bootstrap3開始尽超,全局使用IE盒模型(box-sizing取border-box)官撼,又是基于怎樣的考慮?怎么協(xié)調(diào)好與基于標(biāo)準(zhǔn)盒模型開發(fā)的第三方組件的關(guān)系似谁?
眾所周知,BS2還考慮對(duì)IE7的兼容掠哥,而BS3徹底放棄了對(duì)IE7的兼容巩踏,并將box-sizing設(shè)置為border-box。關(guān)于這一點(diǎn)续搀,可見“Bootstrap 3 released”官方發(fā)布的change list塞琼,摘錄如下:
從以上直白的表述中:Better box model by default(默認(rèn)使用更好的盒模型),我們可以看出BS作者是IE盒模型的擁躉禁舷。作者也把理由羅列了出來彪杉,其核心內(nèi)容也是如前面所提到的,IE盒模型在響應(yīng)式布局上的良好表現(xiàn)牵咙。補(bǔ)充的一點(diǎn)是派近,如果不全局設(shè)置border-box,而每個(gè)組件及其子組件單獨(dú)設(shè)置洁桌,維護(hù)起來將是個(gè)夢(mèng)魘(作者在官方編號(hào)為12351的issure中有提到)渴丸。
而關(guān)于BS如何處理好與基于標(biāo)準(zhǔn)盒模型開發(fā)的第三方組件的關(guān)系,亦可參見編號(hào)為12351的issue:"Move away from * {box-sizing: border-box } to play nice with 3rd party scripts"
作者在issue中另凌,霸氣又委婉地回應(yīng):
1. BS并不考慮對(duì)第三方組件和框架的支持谱轨。作者委婉地說,BS是一個(gè)大項(xiàng)目吠谢,活躍維護(hù)者也主要是四個(gè)人土童,顧不來所有人的需求啊~(但感覺作者是在說,BS是個(gè)又大又全的框架工坊,你丫還搞第三方組件干嘛呀)
2.IE盒模型献汗,用了大家都說好错沃,為什么第三方組件不轉(zhuǎn)過來支持IE盒模型啊(果然是鐵粉)
本章節(jié)從box-sizing的作用雀瓢、瀏覽器兼容性枢析、產(chǎn)生原因、評(píng)價(jià)和最佳實(shí)踐這5個(gè)切入點(diǎn)刃麸,來講解box-sizing屬性醒叁,以期加深各位同學(xué)對(duì)這個(gè)屬性的理解和掌握。特別要強(qiáng)調(diào)的一點(diǎn)是泊业,如果剛接手某個(gè)項(xiàng)目把沼,在編寫CSS代碼前,先看看項(xiàng)目是否有全局配置box-sizing吁伺,并根據(jù)具體的取值來選用相應(yīng)的尺寸計(jì)算規(guī)則饮睬。
5.3. 元素的分類及其布局特性
5.3.1. 元素的分類
從元素的布局特性來分,主要可以分為三類元素:block-level(塊級(jí))元素篮奄、inline-level(行內(nèi)級(jí))元素和inline-block-level(行內(nèi)塊級(jí))元素捆愁,我們可以對(duì)其下個(gè)定義:
5.3.1.1. 塊級(jí)元素
display屬性取block、table窟却、flex昼丑、grid和list-item等值的獨(dú)占一行顯示的元素。
5.3.1.2. 行內(nèi)級(jí)元素
display屬性取inline值的可在同一行內(nèi)排列顯示的元素夸赫。
5.3.1.3. 行內(nèi)塊級(jí)元素
display屬性取inline-block菩帝、inline-table、inline-flex和inline-grid等值的兼具塊級(jí)元素和行內(nèi)級(jí)元素布局特性的元素茬腿。
友情提示:
1)關(guān)于各類元素display的取值呼奢,實(shí)際已全部羅列,但為了保證定義能擁抱變化(未來可能引入新的display屬性值)切平,在羅列時(shí)使用了等字握础;
2)w3c官方文檔,把display屬性值為inline揭绑、inline-block弓候、inline-table的元素,統(tǒng)稱為inline-level元素他匪,我不太喜歡也不太認(rèn)可這種泛泛的分類菇存,本文重新定義了一個(gè)“inline-block-level元素”的概念,來對(duì)“inline-level元素”進(jìn)行了細(xì)分邦蜜,并將inline-blocks依鸥、inline-tables單獨(dú)分類為inline-block-level元素,原文檔如下:“The following values of the 'display' property make an element inline-level: 'inline', 'inline-table', and 'inline-block'.”
5.3.2. 元素的布局特性
5.3.2.1. 塊級(jí)元素(block-level)的布局特性
對(duì)于塊級(jí)元素悼沈,有如下幾個(gè)布局特性:
獨(dú)占一行(width默認(rèn)為100%贱迟,height為0)姐扮;
可以設(shè)置任何尺寸相關(guān)的屬性(width、padding衣吠、margin和border)茶敏;
5.3.2.2. 行內(nèi)級(jí)元素(inline-level)的布局特性
在講行內(nèi)級(jí)元素的布局特性之前,我們先了解一下行內(nèi)級(jí)元素的分類缚俏,其可再細(xì)分兩類元素:
1)可置換行內(nèi)元素
在MDN中惊搏,其對(duì)“可置換行內(nèi)元素”的定義如下:
按字面翻譯,“可置換行內(nèi)元素”忧换,是展示內(nèi)容不在CSS作用域內(nèi)的元素恬惯。這句話是不是不好理解?我們可以換另外一種方式理解:“可置換行內(nèi)元素”亚茬,是這樣一類元素酪耳,其展示的內(nèi)容是通過元素的src、value等屬性或CSS content屬性從外部引用得到的刹缝,可被替換的碗暗。隨著內(nèi)容來源或內(nèi)容數(shù)量的變化,可置換元素本身也會(huì)有水平和垂直方向上尺寸的變化赞草。典型的可替換元素有 <img>
讹堤、 <object>
、 <video>
和 <embed>
厨疙,表單類的可替換元素有<textarea>
和<input>
,某些元素只在一些特殊情況下表現(xiàn)為可替換元素疑务,例如 <audio>
沾凄、<object>、<canvas>
和<applet>知允。
特別地撒蟀,通過 CSS content 屬性來插入的對(duì)象又被稱作 匿名可置換元素。
2)不可置換行內(nèi)元素
“不可置換行內(nèi)元素”其實(shí)就是我們常見的一類行內(nèi)元素温鸽,這一類行內(nèi)元素有<a>和<span>等保屯。“不可置換行內(nèi)元素”是相對(duì)于“可置換行內(nèi)元素”的涤垫,其展示的內(nèi)容是在CSS作用域范圍內(nèi)的姑尺,是不可替換的。
言歸正傳蝠猬,行內(nèi)級(jí)元素有如下幾個(gè)布局特性:
在一行內(nèi)可以與多個(gè)同類型的元素按從左到右的順序排列切蟋;
不可置換行內(nèi)元素不能設(shè)置width、height和垂直方向上的margin榆芦,而可置換行內(nèi)元素則可以柄粹;
在水平和垂直方向上的對(duì)齊方式喘鸟,行內(nèi)級(jí)元素分別受父元素的text-align屬性和自身vertical-align屬性的控制(父元素是table-cell元素時(shí),也受父元素的vertical-align屬性控制)驻右,在水平方向上默認(rèn)左對(duì)齊什黑,在垂直方向上默認(rèn)在行框的baseline基線上顯示(“行框”的概念,會(huì)在后面深入講解)堪夭;
友情提示:
1)有時(shí)候我們不必太糾結(jié)于哪些行內(nèi)元素是可置換行內(nèi)元素愕把,因?yàn)橛行g覽器(如chrome)的默認(rèn)樣式(user agent stylesheet),會(huì)將這一類元素重置為inline-block元素茵瘾,我們可以統(tǒng)一把可置換行內(nèi)元素理解為inline-block元素礼华,因?yàn)槠洳季痔匦耘cinline-block-level元素相同。
2)當(dāng)inline-level元素水平排列時(shí)拗秘,兩兩之間可能會(huì)出現(xiàn)大約6px的空白圣絮,這是由元素間的空白字符(換行符、空格或制表符)產(chǎn)生雕旨,如下圖所示:
清除方法有很多扮匠,本人習(xí)慣用浮動(dòng)的方式來處理,其它方法可自行g(shù)oogle凡涩。
5.3.2.3. 行內(nèi)塊級(jí)元素(inline-block-level)的布局特性
行內(nèi)塊級(jí)元素兼具block-level元素和inline-level元素的布局特性棒搜,主要體現(xiàn)為:
排列方式與行內(nèi)級(jí)元素同,不獨(dú)占一行活箕,在一行內(nèi)按從左到右的順序排列力麸;
水平和垂直方向上的對(duì)齊方式與行內(nèi)級(jí)元素同;
和塊級(jí)元素一樣育韩,可以設(shè)置任何尺寸屬性(但width默認(rèn)為0)克蚂;
注:我們不難發(fā)現(xiàn),其實(shí)可置換行內(nèi)元素筋讨,其布局特性與inline-block-level元素相同埃叭。
5.4. 格式化上下文(Formatting Context)
格式化上下文,它指的是具有某種CSS格式化規(guī)則(布局規(guī)則)的上下文環(huán)境悉罕,在這個(gè)上下文環(huán)境內(nèi)的所有子元素赤屋,都將根據(jù)其特定的CSS格式化規(guī)則來進(jìn)行排列。
我們可以給某個(gè)作為容器的元素指定特定的格式化上下文壁袄,也就是說我們可以定義一個(gè)具有特定布局規(guī)則的渲染區(qū)域类早。常見的格式化上下文有BFC(CSS2.1 規(guī)范)、IFC(CSS2.1 規(guī)范)然想、 FFC(CSS3規(guī)范新增)和GFC(CSS3規(guī)范新增)莺奔,具體介紹如下:
5.4.1. BFC
5.4.1.1. 定義
BFC, 全稱是block formatting context,它是一個(gè)獨(dú)立封閉的渲染區(qū)域,在這個(gè)區(qū)域內(nèi)的所有元素令哟,從區(qū)域的頂部起恼琼,一個(gè)接一個(gè)地根據(jù)自身的布局特性進(jìn)行排列:在這個(gè)區(qū)域內(nèi)的塊級(jí)元素 ,按從上到下的順序顯示屏富,相鄰的塊級(jí)元素可以使用margin隔離晴竞,但在垂直方向上相鄰的塊級(jí)元素會(huì)發(fā)生margin合并;在這個(gè)區(qū)域內(nèi)的inline-level或inline-level-block元素狠半,則按從左到右的順序顯示(W3C組織說BFC內(nèi)部的元素都是一個(gè)接一個(gè)地垂直顯示噩死,我覺得不是很嚴(yán)格火焰,因?yàn)锽FC內(nèi)部也可以容納inline-level和inline-level-block元素当娱,所以這里我的解釋和W3C還是稍微有一些不一樣)。具有BFC格式化環(huán)境的元素阔墩,我們稱之為BFC元素已日,可以說垛耳,BFC定義了BFC元素content區(qū)域的渲染規(guī)則。
看到這段描述飘千,是不是覺得BFC的渲染規(guī)則堂鲜,不就是文檔流的默認(rèn)布局規(guī)則嗎?確實(shí)很像护奈,但不完全等同缔莲。BFC元素內(nèi)部的渲染規(guī)則和普通塊級(jí)元素內(nèi)部的渲染規(guī)則,還是有一些不同的霉旗,我們將在5.4.1.3. 特性一節(jié)詳述痴奏。
5.4.1.2. ****創(chuàng)建方式
創(chuàng)建BFC元素的方式有如下幾種(摘自MDN BFC):
根元素或其它包含它的元素
浮動(dòng)元素 (元素的
float
不是none
)絕對(duì)定位元素 (元素的
position
為absolute
或fixed
)內(nèi)聯(lián)塊 (元素具有
display``: inline-block
)表格單元格 (元素具有
display``: table-cell,HTML表格單元格默認(rèn)屬性
)表格標(biāo)題 (元素具有
display``: table-caption
, HTML表格標(biāo)題默認(rèn)屬性)overflow
值不為visible
的塊元素display``: flow-root
contain
為以下值的元素:layout
,content
, 或strict
彈性項(xiàng) (
display``: flex
或inline-flex
元素的子元素)網(wǎng)格項(xiàng) (
display``: grid
或inline-grid
元素的子元素)多列容器 (元素的
column-count
或column-width
不為auto
厌秒, 包括column-count: 1
的元素)column-span``: all
應(yīng)當(dāng)總是會(huì)創(chuàng)建一個(gè)新的格式化上下文抛虫,即便具有column-span: all
的元素并不被包裹在一個(gè)多列容器中。
5.4.1.3. 特性
BFC元素具有如下特性:
1. 對(duì)應(yīng)一個(gè)獨(dú)立简僧、封閉的渲染區(qū)域,子元素的CSS樣式不會(huì)影響B(tài)FC元素外部雕欺;
舉個(gè)例子岛马,我們分別用連續(xù)的兩個(gè)塊級(jí)元素,一個(gè)是普通塊級(jí)元素屠列,另一個(gè)是BFC元素(均使用綠色背景)啦逆,分別包裹一個(gè)margin-top為20px的子元素(黃色背景),對(duì)比其布局效果:
說明:
普通塊級(jí)元素笛洛,其子元素的margin-top夏志,不會(huì)隔開自身與父元素(普通塊級(jí)元素),但是會(huì)作用到父元素外部(將父元素和叔伯元素或祖父元素隔開)苛让;
BFC元素沟蔑,作為一個(gè)獨(dú)立湿诊、封閉的渲染區(qū)域,其子元素的margin-top瘦材,則會(huì)隔開自身與父元素(BFC元素)厅须,而不會(huì)影響到父元素外部;
2. 浮動(dòng)子元素參與BFC父元素的高度計(jì)算食棕,也就是BFC元素能夠識(shí)別浮動(dòng)元素(將元素聲明為BFC元素朗和,也是clearfix解決父元素塌陷問題的一種常用方法);
舉個(gè)例子:
說明:
BFC元素簿晓,能夠識(shí)別浮動(dòng)子元素眶拉,浮動(dòng)子元素參與BFC元素的高度計(jì)算,不會(huì)出現(xiàn)“高度塌陷”問題憔儿;
普通塊級(jí)元素忆植,不能夠識(shí)別浮動(dòng)子元素,會(huì)出現(xiàn)“高度塌陷”問題皿曲;
- 占據(jù)文檔流的BFC元素(可使用overflow: auto創(chuàng)建)唱逢,能夠識(shí)別浮動(dòng)的兄弟元素;
舉個(gè)例子:
說明:
普通塊級(jí)元素屋休,不能夠識(shí)別浮動(dòng)的兄弟元素坞古,會(huì)被浮動(dòng)的兄弟元素覆蓋部分內(nèi)容;
占據(jù)文檔流的BFC元素(可使用overflow: auto創(chuàng)建)劫樟,能夠識(shí)別浮動(dòng)的兄弟元素痪枫,不會(huì)被浮動(dòng)的兄弟元素覆蓋,與之同行顯示叠艳;
- 占據(jù)文檔流的BFC元素(可使用overflow: auto創(chuàng)建)奶陈,width為auto時(shí),會(huì)占滿當(dāng)前行的剩余寬度附较;
舉個(gè)例子:
說明:
- 文檔流中的BFC元素, width為auto時(shí)吃粒,會(huì)占滿當(dāng)前行的剩余寬度;
5.4.2. IFC
5.4.2.1. 定義
IFC, 全稱是inline formatting context拒课,其內(nèi)部的元素徐勃,在水平方向上,一個(gè)接一個(gè)地顯示早像;在垂直方向上僻肖,每個(gè)元素可以設(shè)置不同的對(duì)齊方式;IFC內(nèi)部的元素卢鹦,被一行行的矩形框所包含臀脏,這些虛擬的矩形框,我們稱為行框(line box)。IFC的作用區(qū)域揉稚,可以看成是包含其所有子元素的行框組成的矩形區(qū)域秒啦。
5.4.2.2. 創(chuàng)建方式
和BFC相比,它的創(chuàng)建方式是被動(dòng)的窃植、隱式的帝蒿,是由所包含的子元素來創(chuàng)建:只有在一個(gè)區(qū)域內(nèi)僅包含可水平排列的元素時(shí)才會(huì)生成,這些子元素可以是文本巷怜、inline-level元素或inline-block-level元素葛超。
5.4.2.3. 特性
1. IFC內(nèi)部的元素,按從左到右延塑、從上到下的順序排布绣张;
2. IFC內(nèi)部的每個(gè)元素,都可以通過設(shè)置vertical-align屬性关带,來調(diào)整在垂直方向上的對(duì)齊侥涵;
3. 包含這些內(nèi)部元素的矩形區(qū)域,形成的每一行宋雏,被稱為line box(行框芜飘,后面會(huì)詳細(xì)介紹);
5.4.3. FFC和GFC
FFC(flex formatting context)和GFC(grid formatting context)磨总,分別是flex布局和grid布局的內(nèi)容嗦明,這兩個(gè)模塊的內(nèi)容非本文介紹的重點(diǎn),所以感興趣的同學(xué)可以自行g(shù)oogle蚪燕。
5.5. 包含塊(Containing Block)
5.5.1. 定義
我們?cè)谠O(shè)置元素尺寸屬性(width娶牌、height、padding馆纳、margin和border)的百分比值或偏移屬性(top诗良、right、bottom和left)的值時(shí)鲁驶,通常會(huì)有一個(gè)“相對(duì)參考系”鉴裹,這個(gè)"相對(duì)參考系"一般是包裹著這個(gè)元素的塊級(jí)祖先元素(一般是塊級(jí)父元素)或離這個(gè)元素最近的非static(relative、absolute和fixed)定位的祖先元素钥弯。這些具有“相對(duì)參考系”作用的祖先元素壹罚,其容納區(qū)域(cotent box或padding box),其實(shí)還有一個(gè)專門術(shù)語形容之寿羞,那就是包含塊(在知識(shí)體系中有個(gè)包含塊的概念,有助于加深對(duì)position定位原理的掌握)赂蠢。
特別地绪穆,relative定位元素,其尺寸屬性(width、height等)的“相對(duì)坐標(biāo)系”仍是其包含塊(塊級(jí)祖先元素(一般是父元素)的content box)玖院,但是偏移屬性(top菠红、right、bottom和left)的“相對(duì)坐標(biāo)系”則是其在文檔流原來的位置难菌。
5.5.2. ICB(initial containing block, 初始包含塊)
5.5.2.1. 定義
如前面所說试溯,任何一個(gè)元素都會(huì)有一個(gè)包含塊作為設(shè)置尺寸屬性和偏移屬性的“相對(duì)參考系”,而對(duì)于頂層的根元素<html />郊酒,沒有任何元素包裹它遇绞,它的包含塊是什么?它選取什么作為“相對(duì)參考系”燎窘?
其實(shí)根元素<html />是有包含塊的摹闽,它是一個(gè)不可見的矩形框,W3C組織稱之為ICB(initial containing block, 初始包含塊)褐健。以下是W3C組織對(duì)ICB對(duì)定義:
The containing block in which the root element lives is a rectangle called the initial containing block.
5.5.2.2. ICB的尺寸和起始位置(左上角坐標(biāo))
在解釋ICB的尺寸和起始位置時(shí)付鹿,在這里先簡(jiǎn)單補(bǔ)充一個(gè)背景知識(shí):連續(xù)媒體(continuous media)和分頁媒體(paged media)。如何理解這兩個(gè)概念蚜迅?在視覺閱讀層面舵匾,它們是展示內(nèi)容的兩種呈現(xiàn)方式。
連續(xù)媒體谁不,就是采用連續(xù)展示內(nèi)容的方式坐梯,它保持了展示內(nèi)容顯示的連續(xù)性(一頁顯示所有內(nèi)容),我們可以在連續(xù)媒體的viewport(可視窗口)查看當(dāng)前呈現(xiàn)的內(nèi)容拍谐。特別地烛缔,瀏覽器窗口就可以看成是連續(xù)媒體,當(dāng)內(nèi)容的尺寸超過viewport時(shí)轩拨,讀者可以通過平滑滾動(dòng)的方式來閱讀內(nèi)容践瓷。
分頁媒體,就是采用切頁展示內(nèi)容的方式亡蓉,它將要展示的內(nèi)容切分為等尺寸的多頁(分頁顯示所有內(nèi)容)晕翠,我們可以在分頁媒體的page area(頁面顯示區(qū)域)查看當(dāng)前呈現(xiàn)的內(nèi)容。特別地砍濒,像幻燈片淋肾、電子書閱讀器,就可以看成是分頁媒體爸邢,當(dāng)內(nèi)容的尺寸超過page area時(shí)樊卓,讀者可以通過切頁的方式來閱讀內(nèi)容;
對(duì)于屬于連續(xù)媒體(continuous media)的瀏覽器窗口來說杠河,ICB的尺寸為viewport(瀏覽器視窗)碌尔,其起始位置為畫布原點(diǎn)(canvas origin浇辜,即首屏的左上角,瀏覽器渲染數(shù)據(jù)后生成的內(nèi)容文檔可以看成是一張畫布)唾戚。
對(duì)于分頁媒體來說柳洋,ICB的尺寸為page area(關(guān)于ICB在分頁媒體的起始位置,沒有找到相關(guān)資料叹坦,但這個(gè)對(duì)于本文來說也不是重點(diǎn))熊镣。
直觀來看,根元素<html />的包含塊ICB募书,就是“首屏”绪囱。
5.5.3. 不同定位元素分別對(duì)應(yīng)的包含塊
static和relative定位元素的包含塊,為其塊級(jí)祖先元素(通常是塊級(jí)父元素)的content box锐膜;
absolute定位元素的包含塊毕箍,為最近的非靜態(tài)定位祖先元素的padding box,查無非靜態(tài)定位祖先元素道盏,那么它的包含塊是ICB(即根元素<html />的包含塊)而柑;
fix定位元素的包含塊,為當(dāng)前viewport(視窗)荷逞;
在這里要強(qiáng)調(diào)的一點(diǎn)媒咳,ICB(初始包含塊)是專有名詞,它特指根元素<html />的包含塊种远。不要將一個(gè)元素的初始包含塊涩澡,錯(cuò)誤理解為它的父元素。MDN的一位編輯者也犯了這種錯(cuò)誤坠敷。具體如下:
經(jīng)修正后:
也有一些權(quán)威CSS書籍說妙同,當(dāng)一個(gè)絕對(duì)定位元素找不到最近的非static祖先元素時(shí),則相對(duì)于根元素<html />定位膝迎,這種說法也是不嚴(yán)謹(jǐn)?shù)闹嘀恪偤每吹揭槐荆缦拢?/p>
圖1. 書的封面
圖2. 原話截圖
我們可以通過一個(gè)簡(jiǎn)單的例子推翻這種說法:將根元素html的高度設(shè)置為超過viewport高度限次,如5000px(假設(shè)viewport高度為500px)芒涡,再將一個(gè)沒有最近的非static祖先元素的絕對(duì)定位元素的bottom設(shè)置為0,尺寸為100px100px即可卖漫。如果真如該書中所言费尽,那么在首屏?xí)r,該絕對(duì)定位元素是被隱藏在滾動(dòng)條下面的羊始。而實(shí)際情況是:該絕對(duì)定位元素必然出現(xiàn)在首屏的底端旱幼,并且會(huì)隨著頁面滾動(dòng)而滾動(dòng)。驗(yàn)證如下:*
****相信這個(gè)謬誤在前端圈流傳已久突委,希望各位同學(xué)引起重視速警。****
5.6. 基本原理
5.6.1. 文檔流(正常流)
5.6.1.1. 定義
關(guān)于“文檔流”叹誉,并沒有找到較為官方的定義。筆者從google搜到一些認(rèn)為比較靠譜的解釋闷旧,羅列如下:
1)摘自:《CSS: understanding the document flow》
**The document flow is the model by which elements are rendered by default in the CSS specifications. In this model, elements are rendered according by their default display rule. In other words, block-level elements are displayed on a new line and inline elements on the same line. Everything is stacked in an ordered way from top to bottom. **
2)摘自:《What is "document flow"?》
Document flow is the arrangement of page elements as defined by positioning statements and the order of html statements; that is, how the different elements take up space and arrange themselves around each other.
在這里我想分享一下我自己對(duì)“文檔流”下的定義:
文檔流,是頁面元素默認(rèn)存放的“容器”钧唐。
****5.6.1.2. 特性
文檔流具有如下特性:
1. 文檔流按照頁面元素書寫的順序忙灼,將頁面元素按從左到右,從上至下的一般順序進(jìn)行排列钝侠,而頁面元素則根據(jù)自身的布局屬性(block-box or inline-box)该园,決定是行內(nèi)顯示,還是換行顯示;
2. 文檔流內(nèi)的元素帅韧,相互尊重:有序排列里初,彼此識(shí)別;
5.6.1.3. 脫離文檔流
元素脫離文檔流忽舟,按我之前下的定義双妨,其實(shí)就意味著:元素脫離了默認(rèn)存放的容器,換到另外一個(gè)容器存放叮阅。一個(gè)元素脫離了文檔流刁品,這樣會(huì)導(dǎo)致:其父元素?zé)o法識(shí)別其,其也不參與父元素高度的計(jì)算浩姥。若有一個(gè)父元素的所有子元素都脫離文檔流挑随,則會(huì)出現(xiàn)“高度塌陷”問題。常見的脫離文檔流的方法有:
將元素設(shè)置為浮動(dòng)元素
將元素設(shè)置為absolute勒叠、fixed元素
5.6.2. 浮動(dòng)(float屬性)
5.6.2.1. 浮動(dòng)元素的分類
根據(jù)float屬性的設(shè)置兜挨,元素可以分為浮動(dòng)元素(值為left或right)和非浮動(dòng)元素(值為none)。而按浮動(dòng)方向劃分眯分,又可細(xì)分為:
左浮動(dòng)元素:float值為left的元素
右浮動(dòng)元素:float值為right的元素
5.6.2.2. 浮動(dòng)原理
要想掌握浮動(dòng)元素的浮動(dòng)原理拌汇,只要理解浮動(dòng)元素的浮動(dòng)起始位置、浮動(dòng)方向和浮動(dòng)結(jié)束位置即可颗搂。
-
浮動(dòng)起始位置
浮動(dòng)元素(包括左右)的浮動(dòng)起始位置担猛,為最后一行最左側(cè)的空白位置,而不管空白位置是否能夠容納當(dāng)前浮動(dòng)元素丢氢;
-
浮動(dòng)方向
左浮動(dòng)元素的浮動(dòng)方向?yàn)閺钠鹗嘉恢孟蜃蟾?dòng)傅联;
右浮動(dòng)元素的浮動(dòng)方向?yàn)閺钠鹗嘉恢孟蛴腋?dòng);
-
浮動(dòng)結(jié)束位置
左浮動(dòng)元素遇到第一個(gè)左浮動(dòng)元素或包含塊的最左側(cè)padding時(shí)疚察,結(jié)束浮動(dòng)蒸走;
右浮動(dòng)元素遇到第一個(gè)右浮動(dòng)元素或包含塊的最右側(cè)padding時(shí),結(jié)束浮動(dòng)貌嫡;
以下demo可以幫助各位同學(xué)理解浮動(dòng)元素的三要素:
/06:layout/float/1. 浮動(dòng)元素三要素.html:
<body>
<div class="fl">左浮動(dòng)元素-1(width: 30%; height: 100px;)</div>
<div class="fl">左浮動(dòng)元素-2(width: 30%; height: 200px;)</div>
<div class="fl">左浮動(dòng)元素-3(width: 30%; height: 100px;)</div>
<div class="fl">左浮動(dòng)元素-4(width: 30%; height: 100px;)</div>
</body>
顯示結(jié)果:
說明:
a. 有四個(gè)連續(xù)左浮動(dòng)的元素比驻,每個(gè)元素寬度為30%该溯;
b. 當(dāng)一行排滿三個(gè)元素時(shí),當(dāng)前行只剩10%的寬度别惦,不足以容納第四個(gè)左浮動(dòng)元素;
c. 第四個(gè)浮動(dòng)元素狈茉,從起始位置(最后一行的最左側(cè)空白)開始向左浮動(dòng),直到遇到第二個(gè)浮動(dòng)元素的邊界;
為了幫助大家理解好浮動(dòng)原理掸掸,在這里我想額外定義幾個(gè)術(shù)語:
左浮動(dòng)隊(duì):由若干個(gè)連續(xù)的左浮動(dòng)元素組成
右浮動(dòng)隊(duì):由若干個(gè)連續(xù)的右浮動(dòng)元素組成
左浮動(dòng)隊(duì)頭元素:左浮動(dòng)隊(duì)的第一個(gè)元素氯庆,也是最左側(cè)的元素
右浮動(dòng)隊(duì)頭元素:右浮動(dòng)隊(duì)的第一個(gè)元素,也是最右側(cè)的元素
特別地扰付,
1. 同一行內(nèi)堤撵,最多有兩條浮動(dòng)隊(duì),一是左浮動(dòng)隊(duì)羽莺,二是右浮動(dòng)隊(duì)实昨;
2. 同一行內(nèi),一條浮動(dòng)隊(duì)可能占滿一行盐固;
3. 連續(xù)浮動(dòng)的若干元素荒给,如果無法在同一行內(nèi)顯示,則會(huì)按行被切分為兩條或更多條浮動(dòng)隊(duì)闰挡;
5.6.2.3. ****浮動(dòng)對(duì)元素display的影響
當(dāng)元素設(shè)置為浮動(dòng)元素后锐墙,可能會(huì)引發(fā)display屬性的值變化,具體規(guī)則如下:
浮動(dòng)元素display屬性變化對(duì)照表
5.6.3. 清除浮動(dòng)(clear屬性)
5.6.3.1. 三要素
清除浮動(dòng)长酗,其作用是改變“當(dāng)前元素”與“前一個(gè)聲明的浮動(dòng)元素”之間的默認(rèn)布局規(guī)則溪北,這種改變主要體現(xiàn)為:讓當(dāng)前元素?fù)Q行顯示。這句話包含三個(gè)要素夺脾,分別為:
使用者:當(dāng)前元素(浮動(dòng)元素或者非浮動(dòng)元素的塊級(jí)元素)
作用對(duì)象(清除誰的浮動(dòng)):前一個(gè)聲明的浮動(dòng)元素
目的(作用):讓當(dāng)前元素?fù)Q行顯示
特別地之拨,為什么使用者不包括非浮動(dòng)的inline元素?因?yàn)榉歉?dòng)的inline元素能夠識(shí)別浮動(dòng)元素咧叭,是否使用clear清除“前一個(gè)聲明的浮動(dòng)元素”的浮動(dòng)蚀乔,其布局結(jié)果是一樣的。感興趣的同學(xué)可以參考:06:layout/clear/4.非浮動(dòng)inline元素清除左浮動(dòng).html菲茬,可以在調(diào)試器中觀察注釋非浮動(dòng)inline元素的clear:left前后吉挣,其顯示位置的變化。而非浮動(dòng)的塊級(jí)元素婉弹,因?yàn)闊o法識(shí)別前面聲明的左浮動(dòng)元素睬魂,故會(huì)和左浮動(dòng)元素發(fā)生重疊(左浮動(dòng)元素在上),所以非浮動(dòng)的塊級(jí)元素使用clear:left清除前一個(gè)左浮動(dòng)元素镀赌,就能避免重疊的現(xiàn)象氯哮。
5.6.3.2. clear屬性的取值及應(yīng)用場(chǎng)景
前面簡(jiǎn)單介紹了clear屬性的作用,是清除前面聲明的浮動(dòng)元素的浮動(dòng)商佛,然后讓當(dāng)前元素?fù)Q行顯示喉钢。但是要具體怎么使用姆打,我們還得深入到clear的屬性值和應(yīng)用場(chǎng)景。
clear屬性的取值有l(wèi)eft肠虽、right和both档插。那么它們的應(yīng)用場(chǎng)景分別是什么堪嫂?
left值的應(yīng)用場(chǎng)景是介返,前面聲明的浮動(dòng)元素是向左浮動(dòng)(float: left);
right的應(yīng)用場(chǎng)景是蔗彤,前面聲明的浮動(dòng)元素是向右浮動(dòng)(float: right);
both的應(yīng)用場(chǎng)景是供置,前面聲明的浮動(dòng)元素的浮動(dòng)方向不確定污茵,可能是左搞莺,也可能是右(了解過clearfix實(shí)現(xiàn)原理的同學(xué)更哄,就不難明白)邢笙;
再次強(qiáng)調(diào)一下啸如,當(dāng)前元素如果要清除浮動(dòng),清除的是前面聲明的浮動(dòng)元素的浮動(dòng)氮惯,其clear屬性要取什么值叮雳,跟當(dāng)前元素的是否是浮動(dòng)元素或浮動(dòng)方向沒有任何關(guān)系,而取決于其前面聲明的浮動(dòng)元素的浮動(dòng)方向妇汗。
舉個(gè)例子帘不,一個(gè)右浮動(dòng)元素(float:right),前面有一個(gè)左浮動(dòng)元素(float:left)杨箭,如果這個(gè)右浮動(dòng)元素使用clear: left時(shí)寞焙,這個(gè)元素會(huì)清除前一個(gè)元素的浮動(dòng),進(jìn)而換行顯示互婿;如果使用clear:left時(shí)捣郊,這個(gè)元素在當(dāng)前行的最右端顯示。如下圖所示(06:layout/clear/4.右浮動(dòng)清除左浮動(dòng).html):
圖1. 右浮動(dòng)清除左浮動(dòng)
圖2.右浮動(dòng)元素清除右浮動(dòng)
在了解完clear屬性的取值和應(yīng)用場(chǎng)景慈参,我們可以對(duì)其作用呛牲,可以總結(jié)為:
如果當(dāng)前元素浮動(dòng)元素或非浮動(dòng)的塊級(jí)元素,且前面聲明的元素是左(右)浮動(dòng)元素驮配,那么當(dāng)前元素可以使用clear: left(clear: right)娘扩,清除前一個(gè)左(右)浮動(dòng)元素的左(右)浮動(dòng),此時(shí)當(dāng)前元素會(huì)換行顯示壮锻;如果當(dāng)前元素clear的浮動(dòng)與前面一個(gè)浮動(dòng)元素的浮動(dòng)方向不同向琐旁,當(dāng)前元素不會(huì)換行;
5.6.3.3. 清除浮動(dòng)后的margin合并問題
1)兩個(gè)浮動(dòng)元素之間躯保,其垂直方向上的margin不會(huì)發(fā)生合并旋膳,如下圖所示:
浮動(dòng)元素間會(huì)不發(fā)生垂直margin合并
2)非浮動(dòng)的塊級(jí)元素和浮動(dòng)元素之間,其垂直方向上的margin會(huì)發(fā)生合并途事,如下圖所示:
非浮動(dòng)的塊級(jí)元素與浮動(dòng)元素間會(huì)發(fā)生margin合并
特別地验懊,MDN的文檔說非浮動(dòng)的塊級(jí)元素與浮動(dòng)元素間不會(huì)發(fā)生margin合并擅羞,實(shí)際上會(huì),上述結(jié)果已經(jīng)證明义图,已在MDN上更正該錯(cuò)誤减俏。以下為MDN未修改前的原話:
MDN未修正前的原話
5.6.3.4. 清除浮動(dòng)的特殊應(yīng)用:解決父元素高度塌陷問題
眾所周知,當(dāng)一個(gè)父元素里面的所有元素都是浮動(dòng)元素時(shí)碱工,此時(shí)父元素?zé)o法識(shí)別這些浮動(dòng)子元素娃承,會(huì)進(jìn)一步導(dǎo)致父元素發(fā)生高度塌陷問題。一種通用的解決方案就是在父元素內(nèi)部的尾部append一個(gè)非浮動(dòng)的怕篷、尺寸為0的塊級(jí)元素(后面簡(jiǎn)稱fix元素)历筝,然后使用clear:both,讓這個(gè)fix元素?fù)Q行顯示廊谓,進(jìn)而讓父元素能夠識(shí)別前一行的高度梳猪。這種樸素的方案其實(shí)就是clearfix的基本原理,clearfix只是更加優(yōu)雅地用:after來實(shí)現(xiàn)fix元素蒸痹。
特別說明:解決父元素高度塌陷問題春弥,還可以通過將父元素聲明為BFC元素來實(shí)現(xiàn)。
5.6.4. 定位(position屬性)
5.6.4.1. 定位元素的分類
根據(jù)position屬性的取值叠荠,static(默認(rèn)值)匿沛、relative、absolute榛鼎、fixed逃呼,元素可以分為靜態(tài)定位元素(值為static)、相對(duì)定位元素(值為relative)借帘、絕對(duì)定位元素(值為absoute)和固定定位元素(值為fixed)蜘渣。
注:position的取值還有sticky,但I(xiàn)E11都不支持肺然,此處不講
5.6.4.2. 定位原理
static定位元素定位時(shí)的相對(duì)坐標(biāo)系:無法設(shè)置top蔫缸、right、bottom和left這四個(gè)偏移屬性际起;
relative定位元素定位時(shí)的相對(duì)坐標(biāo)系:元素在文檔流原來的位置(區(qū)域)拾碌;
absolute定位元素定位時(shí)的相對(duì)坐標(biāo)系:離元素最近的一個(gè)非static(包含relative、absolute和fixed)定位祖先元素(包含塊為其padding box)街望,如果沒有則為ICB(初始包含塊)校翔,即根元素html的包含塊;
fixed定位元素定位時(shí)的相對(duì)坐標(biāo)系:當(dāng)前的視窗(viewport)灾前;
5.6.5. line box(行框)
5.6.5.1. 定義
前面在介紹IFC時(shí)防症,我們提到過line box的定義:包含IFC內(nèi)部的所有子元素的虛擬矩形區(qū)域,形成的每一行,稱為line box蔫敲。由于它是矩形的饲嗽,中文常見將之翻譯為行框。
5.6.5.2. 模型結(jié)構(gòu)(七線譜)
line box的模型結(jié)構(gòu)奈嘿,形如七線譜貌虾,其中有六條重要的線:top線、text-top線裙犹、middle線尽狠、baseline線、text-bottom線和bottom線叶圃,如下圖所示:
行框七線譜
其中top線到text-top線的區(qū)域和bottom線到text-bottom的區(qū)域袄膏,又稱為行半距(half-leading),兩個(gè)行半距之和掺冠,為一個(gè)行距哩陕;text-top線到text-bottom線的區(qū)域,稱之為內(nèi)容區(qū)域(content-area)赫舒。如下圖所示:
行框區(qū)域劃分
****5.6.5.3. 行框高度的計(jì)算****
行框的高度,即一行的top線和bottom線間的垂直距離闽瓢,這個(gè)垂直距離為:上下兩個(gè)行半距的高度和一個(gè)內(nèi)容區(qū)域的高度之和接癌。影響行框高度計(jì)算的因素來自兩方面,一是自身line-height屬性的設(shè)置扣讼,二是內(nèi)部inline-level子元素的margin box高度的取值和line-height缺猛、vertical-align兩個(gè)屬性的設(shè)置。關(guān)于其計(jì)算規(guī)則椭符,具體羅列如下:
1. 一個(gè)元素的行框高度荔燎,可由該元素的line-height屬性設(shè)置;
- 一個(gè)元素的行框高度销钝,受不可置換(span有咨、a、label等)的子元素的內(nèi)容高度(text-top到text-bottom的垂直距離)影響(內(nèi)容高度又受font-size屬性和瀏覽器的解析規(guī)則影響蒸健,但主要由font-size決定座享;相同的font-size,在不同的瀏覽器似忧,計(jì)算出來的內(nèi)容高度也不一樣渣叛,最終導(dǎo)致的行框高度也不一樣);
3. 一個(gè)元素的行框高度盯捌,可由不可置換(span淳衙、a、label等)的子元素的line-height屬性設(shè)置;
- 一個(gè)元素的行框高度箫攀,可由可置換行內(nèi)元素(如img)或display屬性為inline-block肠牲、inline-table的這一類inline-block-level子元素的margin box高度和vertical-align屬性決定,當(dāng)vertical-align為top或bottom時(shí)匠童,行框的高度達(dá)到最小埂材,剛好為子元素的margin box高度;
圖1. img元素的margin box高度比行框高度小
圖2. img元素的margin box高度與行框高度一致汤求,行框高度達(dá)到最小
5. 如果同時(shí)滿足以上設(shè)置條件俏险,那么行框的高度取最大值;
友情提示:在圖1 img元素的margin box高度比行框高度小扬绪,我們會(huì)看到img元素到父元素的底端會(huì)有一段空白竖独,為什么會(huì)有這種現(xiàn)象?張?chǎng)涡窭蠋熢凇禖SS深入理解vertical-align和line-height的基友關(guān)系》一文中將之定義為“幽靈空白節(jié)點(diǎn)”挤牛,其實(shí)結(jié)合行框理論來解釋莹痢,這段空白并不“幽靈”,也很好理解:它是行框的baseline線到bottom線的垂直距離墓赴,可置行內(nèi)換元素如img和inline-block-level元素竞膳,在被瀏覽器解析時(shí),會(huì)和“文本”一樣诫硕,默認(rèn)在baseline線上顯示坦辟,而不是在行框的bottom線上。
舉個(gè)例子: 行框高度的計(jì)算
html:
<style>
.line-box {
background: yellow;
line-height: 32px;
font-size: 20px;
}
.span-1 {
line-height: 40px;
background: red;
}
.span-2 {
line-height: 38px;
background: green;
}
img {
width: 50px;
height: 50px;
}
</style>
<body>
<div class="line-box">
<span class="span-1">span(line-height: 40px)</span>
<span class="span-2">span(line-height: 38px)</span>
</div>
<div class="line-box">
<span class="span-1">span(line-height: 40px)</span>
<span class="span-2">span(line-height: 38px)</span>
<img src="#" />
</div>
</body>
顯示結(jié)果(chrome下):
圖1. line box內(nèi)部?jī)H有不可置換元素
圖2. line box內(nèi)部還有可置換元素img
說明:
a. 元素每一行的line-height章办,既可以由當(dāng)前元素的line-height屬性設(shè)置(32px)锉走,也可以由該行子元素的line-height屬性設(shè)置(分別是40px和38px),但取最大的line-height(40px)藕届,如圖1所示挪蹭;
b. 特別地,如果一行內(nèi)還有可以設(shè)置height的可置換元素如img(height: 50px)休偶,且img的高度大于設(shè)置的最大line-height(40px)時(shí)梁厉,那么該行會(huì)被撐高,瀏覽器會(huì)重新計(jì)算line-height(最終結(jié)果為63px)踏兜,如圖2所示懂算;
******5.6.5.4.**** 與line box行框有關(guān)的兩個(gè)重要屬性:line-height和vertical-align**
相信很多前端同學(xué)有這樣的感覺:line-height和vertical-align這兩個(gè)屬性總是形影不離,而且有著一種說不清的關(guān)系庇麦。
它們到底有什么聯(lián)系嗎计技?
其實(shí)這兩個(gè)屬性的關(guān)系可由行框和行框內(nèi)的inline-level元素來體現(xiàn)。line-height屬性決定inline-level元素所在行框的高度山橄,它是inline-level元素在一行內(nèi)垂直方向上的顯示范圍垮媒;vertical-align屬性則決定inline-level元素在一行內(nèi)的垂直對(duì)齊方式,即決定inline-level元素在一行內(nèi)垂直方向上的最終位置。下面我們來深入介紹這兩個(gè)屬性:
1)line-height屬性
1.1)line-height屬性的作用
line-height屬性一般用于塊級(jí)元素設(shè)置其內(nèi)部每一行的高度睡雇,即默認(rèn)行高萌衬;line-height屬性也可以用于不可置換元素(如span、a)設(shè)置所在行框的高度它抱。也就說秕豫,每一行計(jì)算出來的最終行高,既受父元素line-height屬性的影響观蓄,也受子元素line-height屬性的影響混移。
1.2)line-height屬性的取值
line-height的取值有<length>、<number>侮穿、<percentage>和關(guān)鍵字normal(默認(rèn)值)歌径。其中:
<length>表示使用指定帶單位的長(zhǎng)度來設(shè)置line-height,這些長(zhǎng)度單位可以是px亲茅、pt和em和rem回铛;
<number>表示用font-size值的倍數(shù)來設(shè)置line-height;
<percentage>表示用font-size值的百分比來設(shè)置line-height克锣;
而關(guān)鍵字normal茵肃,其最終計(jì)算出來的尺寸,則取決于瀏覽器各自的解析機(jī)制和選用的font-family類型:瀏覽器會(huì)根據(jù)選用的font-family類型來計(jì)算出一個(gè)合適的值袭祟,W3C官方推薦使用<number>值免姿,并且推薦值的范圍為1.0到1.2之間(但經(jīng)過實(shí)測(cè),瀏覽器在實(shí)現(xiàn)時(shí)榕酒,遠(yuǎn)比這個(gè)復(fù)雜,而且不同瀏覽器間也存在差異故俐。唯一可以確定的一點(diǎn)是想鹰,最終的行高肯定會(huì)比font-size值要大)。
我們?cè)趯I稿實(shí)現(xiàn)為頁面代碼時(shí)药版,常常強(qiáng)調(diào)要Pixel Perfect辑舷、高精準(zhǔn)地還原設(shè)計(jì)稿。但
我們常常會(huì)遇到這樣一個(gè)問題:當(dāng)我們用一個(gè)塊級(jí)元素包裹文本時(shí)槽片,會(huì)發(fā)現(xiàn)塊級(jí)元素的高度何缓,實(shí)際比文本的font-size尺寸還要高,導(dǎo)致上下形成了一些空白还栓,進(jìn)一步造成塊級(jí)元素內(nèi)的文本與垂直方向上相鄰元素的距離變大碌廓,如下圖所示:
line-height值為normal
這種誤差是由于line-height的默認(rèn)值為normal,那有什么辦法可以解決這個(gè)問題呢剩盒?較常用的方法是將塊級(jí)元素的line-height設(shè)置為1或100%谷婆。設(shè)置后的結(jié)果如下圖所示:
line-height值為1或100%
這樣做也有一點(diǎn)不好,那就是:瀏覽器最終解析出來的內(nèi)容高度,有可能是比font-size要大的纪挎,當(dāng)行高為font-size時(shí)期贫,文本內(nèi)容就會(huì)溢出。我們將字體放大為100px异袄,溢出效果就很明顯通砍,如下圖所示:
line-height值為1或100%
1.2)line-height屬性對(duì)元素高度的影響
我們可以通過了解line-height屬性分別對(duì)塊元素和不可置換的行內(nèi)元素自身高度的影響、以及不可置換的子元素的line-height屬性對(duì)父元素高度的影響烤蜕,來深入理解line-height屬性的作用封孙。
為了幫助大家更好地理解line-height,我設(shè)計(jì)了如下三個(gè)小demo:
demo1: line-height屬性對(duì)塊級(jí)元素自身height的影響
html:
</body>
**// div為單行**
<div class="block">
div(line-height: 32px)
</div>
**// div為多行**
<div class="block">
div(line-height: 32px)
<br>
div(line-height: 32px)
</div>
</body>
顯示結(jié)果(chrome下):
圖1. div為單行時(shí)
圖2. div為多行時(shí)
說明:
a. 當(dāng)一個(gè)塊元素不設(shè)置height玖绿,而且這個(gè)塊元素僅有一行時(shí)敛瓷,那么其height剛好等于line-height;
b. 當(dāng)一個(gè)塊元素不設(shè)置height斑匪,而且這個(gè)塊元素有多行時(shí)呐籽,那么其height剛好等于每一行的line-height之和;
demo2: line-height屬性對(duì)不可置換行內(nèi)元素(如span)的height的影響
html:
<div class="line-box">
<span class="inline-element">
span(line-height: 40px;font-size: 20px)
</span>
</div>
顯示結(jié)果:
圖1. 行內(nèi)元素為單行時(shí)蚀瘸,height為28px(在chrome下)
圖2. 行內(nèi)元素單行時(shí)狡蝶,height為20.5px(在firefox下)
說明:
a. 不可置換行內(nèi)元素為單行時(shí),其height等于text-top線到text-bottom線的距離贮勃,所以line-height的取值不會(huì)影響到其height贪惹,其height由font-size和瀏覽器的默認(rèn)解析機(jī)制決定(一般>font-size,大多少則取決于瀏覽器解析機(jī)制寂嘉,如圖1奏瞬、2所示);
b. 不可置換元素為多行時(shí)泉孩,其height等于第一行的text-top線到最后一行的text-bottom線的距離硼端,此時(shí)line-height的取值就會(huì)影響到其height,其height=line-height * 行數(shù) - (line-height - 每一行text-top線到text-bottom的距離)寓搬,即height=line-height * 行數(shù) - 2 * half-heading珍昨;如下圖所示:
圖3. 行內(nèi)元素為多行時(shí)(在chrome下)
demo3:不可置換的子元素(如span)的line-height,對(duì)父元素height的影響
html:
<div class="line-box">
<span class="span-1">span(line-height: 40px)</span>
<span class="span-2">span(line-height: 38px)</span>
<br>
<span class="span-3">span(line-height: 50px)</span>
</div>
顯示結(jié)果(chrome下):
說明:
a. 塊級(jí)元素每一行的行高都可以不同;
b. 不可置換的行內(nèi)子元素的line-height屬性句喷,可以決定所在行框的高度;
c. 如果一個(gè)父元素不設(shè)置height镣典,那么其height為所有行的高度之和;
d. 不可置換的行內(nèi)子元素的line-height屬性唾琼,是通過影響行框的高度來影響父元素的高度的兄春。
2)vertical-align屬性
vertical-align的作用之一:就是用于設(shè)置inline-level元素自身在“行框”內(nèi)的垂直對(duì)齊方式,其控制范圍在一行內(nèi)锡溯。較常用的值有top神郊、middle肴裙、baseline(默認(rèn)值)和bottom,不常用的有text-top涌乳、text-bottom蜻懦、sub和super,幾乎不用的有<length>和<percentage>夕晓。
行框七線譜
vertical-align屬性的幾個(gè)重要取值的作用如下:
當(dāng)vertical-align取top時(shí)宛乃,表示當(dāng)前inline-level元素的上margin edge在行框內(nèi)貼頂;
當(dāng)vertical-align取bottom時(shí)蒸辆,表示當(dāng)前inline-level元素的下margin edge在行框內(nèi)貼底征炼;
當(dāng)vertical-align取middle時(shí),表示當(dāng)前inline-level元素的垂直平分線和行框的middle線重合躬贡;
當(dāng)vertical-align取baseline時(shí)谆奥,表示當(dāng)前inline-level元素的下margin edge緊貼在行框的baseline上;
vertical-align屬性的另一個(gè)作用:就是table-cell元素用于控制其內(nèi)部子元素在垂直方向上的對(duì)齊方式拂玻,而且這些子元素的類型不受限制酸些,不僅可以是span,而且可以是div檐蚜。
舉個(gè)例子:
html:
<table>
<tr>
<td class="top">div(top)</td>
<td class="middle">div(middle)</td>
<td class="baseline">div(baseline)</td>
<td class="bottom">div(bottom)</td>
</tr>
</table>
顯示結(jié)果:
說明:
a. table-cell元素通過設(shè)置自身的vertical-align屬性魄懂,來設(shè)置其子元素在垂直方向上的對(duì)齊方式;
特別說明:我們常用說的使用table布局來實(shí)現(xiàn)子元素在父元素內(nèi)部垂直居中闯第,就是運(yùn)用到了這個(gè)知識(shí)點(diǎn)市栗。
5.6.6. margin
在傳統(tǒng)的布局方案中,margin不僅用來隔離自身與相鄰元素或父元素(一般不推薦用來隔離父元素)咳短,而且在元素水平和垂直方向上的居中定位填帽,亦發(fā)揮了重要的作用。下面我們來深入介紹margin的相關(guān)布局特性咙好。
5.6.6.1. auto的計(jì)算規(guī)則(在width和margin上使用)
1)水平方向上
談到“如何設(shè)置文檔流中的塊級(jí)元素在父元素內(nèi)部水平居中篡腌?”這個(gè)布局問題,相信很多同學(xué)馬上會(huì)想到這個(gè)方案:給元素設(shè)置固定寬度敷扫,并使用margin: 0 auto(水平方向上的margin為auto)
.child {
width: 100px;
margin: 0 auto;
}
它的實(shí)現(xiàn)原理,包含如下四個(gè)基礎(chǔ)知識(shí)點(diǎn):
- 塊級(jí)元素的水平尺寸(outerWidth诚卸,margin box的寬度)的計(jì)算規(guī)則:
outerWidth = margin-left + border-left-width + padding-left + width + padding-right + border-right + margin-right葵第,如下圖所示:
文檔流中的塊級(jí)元素,其在水平方向上的尺寸屬性的初始值合溺,僅width為auto卒密,其余為0
在水平方向上的尺寸屬性,僅width棠赛、margin-left和margin-right可以設(shè)置auto值(自動(dòng)計(jì)算)
文檔流中的塊級(jí)元素哮奇,其在水平方向上的尺寸屬性膛腐,當(dāng)值為auto時(shí),表示取所在行的剩余寬度鼎俘,特別地哲身,當(dāng)margin-left和margin-right的值均為auto時(shí),會(huì)平分所在行的剩余寬度
在理解了上述四個(gè)基礎(chǔ)知識(shí)點(diǎn)贸伐,我們不難理解其原理:
當(dāng)塊級(jí)元素在水平方向上的尺寸屬性勘天,除了margin-left和margin-right值為auto,其余皆為定值捉邢,那么margin-left和margin-right會(huì)自動(dòng)平分父元素的剩余寬度脯丝,進(jìn)而達(dá)到在父元素內(nèi)部水平居中的效果,如下圖所示:
圖1. 元素在父元素內(nèi)部水平居中(左右margin各取一半)
圖2. 水平居中元素的盒模型解構(gòu)圖
結(jié)合上述四個(gè)基礎(chǔ)知識(shí)點(diǎn)伏伐,我們還可以得出如下結(jié)論:
文檔流中的塊級(jí)元素如果不設(shè)置任何水平尺寸屬性宠进,那么其默認(rèn)的width為當(dāng)前行的content width,此時(shí)width取auto和100%藐翎,最終的計(jì)算值一樣
2)垂直方向上
或許我們都曾問過這樣的一個(gè)問題:既然可以通過設(shè)置margin: 0 auto材蹬,讓文檔流中的塊級(jí)元素在父元素內(nèi)部水平居中,那么可否通過設(shè)置margin: auto 0阱高,讓其垂直居中赚导?
答案是不能的,因?yàn)槲臋n流中的塊級(jí)元素赤惊,其垂直方向上的margin為auto時(shí)的計(jì)算規(guī)則和在水平方向上的計(jì)算規(guī)則不同:不取父元素剩余的高度吼旧,而為0。W3C標(biāo)準(zhǔn)原話如下:
“If “margin-top” or “margin-bottom” is “auto”, their used value is 0″
或許大家會(huì)問未舟,為什么要這樣設(shè)計(jì)呢圈暗?官方并沒有給出說明,但是有網(wǎng)友給出了如下幾個(gè)解釋裕膀,羅列如下员串,供各位參考(可以在留言中分享你的看法,本人比較認(rèn)同第一條):
It could be because of the typical vertical page flow, where page size increases height-wise. So, centering an element vertically in its container is not going to make it appear centered, relative to the page itself, unlike when it’s done horizontally (in most cases).
And maybe it’s because of this same reason, they decided to add an exception for absolute elements which can be centered vertically along the entire page’s height.
It could also be because of the margin collapse effect (a collapse of adjacent elements” margins) which is another exception for the vertical margins.
在W3C標(biāo)準(zhǔn)規(guī)約中昼扛,雖不能使用margin: auto 0寸齐,實(shí)現(xiàn)普通文檔流中的塊級(jí)元素在父元素內(nèi)部垂直居中缚陷,但是可以使用margin: auto 0谆刨,實(shí)現(xiàn)絕對(duì)或固定定位元素在包含塊內(nèi)部垂直居中,因?yàn)榻^對(duì)或固定定位元素垂直方向上的margin轧飞,其 auto仍會(huì)取包含塊的剩余高度蛹含,W3C官方文檔給出的計(jì)算公式如下:
'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
等價(jià)的簡(jiǎn)化公式:
子元素outerHeight = 包含塊height - 子元素top - 子元素bottom
提示:
1. 子元素outerHeight毅厚,是指當(dāng)前子元素margin box的高度;
2. 包含塊height浦箱,可以為當(dāng)前子元素的相對(duì)定位參考系元素的padding box的高度吸耿、ICB的高度或viewport的高度祠锣;
要使用上述規(guī)則來實(shí)現(xiàn)子元素在父元素內(nèi)部垂直居中,那么就需要保證:
子元素的top值 + bottom值為0(原因:讓子元素outerHeight 等于包含塊height)
子元素的top值取0(原因:讓子元素的上margin edge緊貼包含塊的頂部)
下面通過一個(gè)demo來詳細(xì)介紹:
html:
<style>
.parent {
position: relative;
background: yellow;
height: 100px;
}
.child {
position: absolute;
top: 0;
bottom: 0;
background: green;
width: 140px;
height: 20px;
margin: auto 0;
text-align: center;
}
</style>
<body>
<div class="parent">
<div class="child">垂直居中的子元素</div>
</div>
</body>
顯示結(jié)果:
圖1. 子元素在父元素內(nèi)部垂直居中(上下margin各取一半)
圖2. 垂直居中元素的盒模型解構(gòu)圖
說明:
a. 絕對(duì)定位的子元素的top為0咽安,其輪廓(包含margin)的上邊界與其包含塊內(nèi)容區(qū)域的頂部緊貼伴网;
b. 由已知求未知:包含塊的height已知,子元素的top值和bottom值之和為0板乙,即子元素的outerHeight可求是偷,又因?yàn)樽釉豩eight已知,故垂直方向上的剩余高度可以確定募逞,當(dāng)子元素的margin-top和margin-bottom均為auto時(shí)蛋铆,將平分剩余的高度;
5.6.6.2. ****margin合并(margin collapsing)
在垂直方向上放接,元素與自身或相鄰的兄弟元素刺啦、父元素、子元素的margin纠脾,會(huì)發(fā)生合并(注意:在IE6/7子元素垂直方向上的margin會(huì)隔離父元素玛瘸,而不是和父元素的margin發(fā)生合并,IE8+則與標(biāo)準(zhǔn)瀏覽器同)苟蹈,margin取較大的值糊渊,而在水平方向上則不會(huì)。各位讀者可以從下面三個(gè)demo慧脱,來理解垂直方向上margin的合并:
- 父元素與子元素(第一個(gè)子元素渺绒、最后一個(gè)子元素)
html:
<div class="wrapper">
<div class="parent">
<div class="child first-child">第一個(gè)子元素(margin-top: 20px)</div>
<div class="child last-child">最后一個(gè)子元素(margin-bottom: 20px)</div>
</div>
</div>
顯示結(jié)果:
說明:
a. 父元素(黃色)的margin-top(40px)和第一個(gè)子元素的margin-top(20px)發(fā)生融合(取較大的40px);
b. 父元素(黃色)的margin-bottom(40px)和最后一個(gè)子元素的margin-bottom(20px)發(fā)生融合(取較大的40px)菱鸥;
- 上下相鄰的兄弟元素(同層元素)
html:
<div class="parent">
<div class="child first-child">第一個(gè)元素(margin-bottom: 40px)</div>
<div class="child last-child">第二個(gè)元素(margin-top: 20px)</div>
</div>
顯示結(jié)果:
說明:
a. 第一個(gè)元素的margin-bottom(40px)和第二個(gè)元素的margin-top(20px)發(fā)生融合(取較大的40px)宗兼;
- 空塊級(jí)元素
html:
<div class="line">第一行</div>
<div class="empty-block"></div>
<div class="line">第二行</div>
顯示結(jié)果:
說明:
a. 兩行之間的空白區(qū)域,為一個(gè)空塊元素氮采;
b. 空塊的margin-top為40px, margin-bottom為20px;
c. 兩行之間的距離為40px殷绍,可知空塊元素的margin-top和margin-bottom發(fā)生了合并,取較大值鹊漠;
這里我們舉了三個(gè)會(huì)在垂直方向上發(fā)生margin合并的例子主到,但是細(xì)心的同學(xué)可能記得,我們?cè)?strong>“5.6.3.3. 清除浮動(dòng)后的margin合并問題”章節(jié)躯概,舉了一個(gè)在垂直方向上例子不會(huì)發(fā)生margin合并的例子:浮動(dòng)元素間在垂直方向上不會(huì)發(fā)生margin合并登钥。
5.6.6.3. 子元素的margin隔離父元素
細(xì)心的讀者不難發(fā)現(xiàn),在“2) 上下相鄰的兄弟元素(同層元素)” 的demo可以看到
子元素(綠色)垂直方向上的margin并沒有將自己與父元素(黃色)隔離開(IE6/7會(huì)楞陷,IE8+不會(huì))怔鳖。
那么什么情況茉唉,子元素的margin可以和父元素隔離開固蛾?
首先要強(qiáng)調(diào)的一點(diǎn)是结执, 子元素水平方向上的margin,始終能夠隔離父元素艾凯;然而子元素在垂直方向上的margin隔離父元素的情況献幔,本人記錄的僅有以下四種(歡迎補(bǔ)充):
case 1: 父元素是BFC元素
html:
<div class="parent">
<div class="child">子元素(margin: 20px)</div>
</div>
顯示結(jié)果:
說明:
a. 父元素(黃色)是BFC元素,子元素(綠色)垂直方向上的margin能夠隔離父元素趾诗;
case 2:父元素?fù)碛衎order
html:
<div class="parent">
<div class="child">子元素(margin: 20px)</div>
</div>
顯示結(jié)果:
說明:
a. 父元素(黃色)擁有border蜡感,子元素(綠色)垂直方向上的margin能夠隔離父元素;
case 3:父元素?fù)碛衟adding
html:
<div class="parent">
<div class="child">子元素(margin: 20px)</div>
</div>
顯示結(jié)果:
說明:
a. 父元素(黃色)擁有padding恃泪,子元素(綠色)垂直方向上的margin能夠隔離父元素郑兴;
case 4:子元素是可置換元素或display為inline-block、inline-table贝乎、table-caption的元素
html:
<style>
.parent {
background: yellow;
width: 100%;
height: 60px;
line-height: 20px;
}
.inline-block {
display: inline-block;
}
.inline-table {
display: inline-table;
}
img, .inline-block, .inline-table {
border: 1px solid green;
height: 20px;
min-width: 20px;
margin-top: 10px;
vertical-align: top;
}
</style>
<body>
<div class="parent">
<img src="frame_image.svg" />
<div class="inline-block">display: inline-block </div>
<div class="inline-table">display: inline-table</div>
</div>
</body>
顯示結(jié)果:
說明:
a. 可置換行內(nèi)的和display屬性為inline-block情连、inline-table的子元素,其垂直方向上的margin能夠隔離自身與父元素览效;
在這里對(duì)margin合并和margin隔離作一個(gè)小結(jié)却舀,本人把遇到過的所有在垂直方向上會(huì)發(fā)生與不會(huì)發(fā)生margin合并、能使用margin隔離與不能使用margin隔離的例子锤灿,都羅列了出來(然而這僅僅是在標(biāo)準(zhǔn)瀏覽器的例子挽拔,在IE6/7情況還會(huì)不一樣,但因?yàn)楝F(xiàn)在基本無需再兼容低版本的IE但校,所以就不再列舉)螃诅。目的不是讓大家記住它,而是讓大家避開它:在垂直方向上始腾,兄弟元素間盡量不要設(shè)置相鄰的margin州刽,子元素也不要使用margin來隔離父元素,這樣能盡量保證你的CSS代碼浪箭,在各種版本的瀏覽器都有較好的兼容性(顯示一致)穗椅。
7. 結(jié)尾語
本文從CSS盒模型及其發(fā)展史、元素的分類及其布局特性奶栖、格式化上下文(Formatting Context)匹表、包含塊、基本原理(文檔流宣鄙、浮動(dòng)袍镀、清除浮動(dòng)、定位冻晤、行框苇羡、margin)這五大模塊,系統(tǒng)介紹了一下前端的布局基礎(chǔ)鼻弧,希望此次分享设江,能夠讓各位讀者對(duì)前端基礎(chǔ)布局有一個(gè)底層锦茁、體系的認(rèn)識(shí)。因?yàn)閮?nèi)容涵蓋過廣叉存,難免會(huì)有紕漏码俩,還望見諒和指正。
此篇文章斷斷續(xù)續(xù)寫了幾個(gè)月歼捏,從年前寫到年后稿存,一方面是因?yàn)檫@個(gè)標(biāo)題太大,含括的內(nèi)容太多瞳秽,需要慢慢梳理瓣履;一方面是文中要講的東西,很多是出于本人的感悟和總結(jié)练俐,為了保證觀點(diǎn)的正確性拂苹、嚴(yán)謹(jǐn)性以及和行業(yè)的標(biāo)準(zhǔn)術(shù)語做好同步,需逐一驗(yàn)證痰洒;還有一方面也是近幾個(gè)月來瓢棒,本人需要處理的私事較多,分散了精力丘喻。
時(shí)隔半年脯宿,依然有不少朋友還在關(guān)注我的公眾號(hào),謝謝你們的支持泉粉。這遲來的一篇分享连霉,希望能對(duì)各位有用,后面我也會(huì)努力分享更多對(duì)大家有幫助的文章嗡靡。
最后我還想再分享一些心得體會(huì):
-
不要輕視簡(jiǎn)單的東西
我們?cè)谏钪锌偸侨菀缀雎砸恍┖?jiǎn)單的東西跺撼,因?yàn)檩p視簡(jiǎn)單,導(dǎo)致過了幾年依然也沒有掌握讨彼,前端的同學(xué)更應(yīng)該注意這一點(diǎn)歉井。
-
盡信書不如無書
不要太相信權(quán)威,而是要學(xué)會(huì)驗(yàn)證哈误、總結(jié)哩至,并構(gòu)建自己的知識(shí)體系。
-
學(xué)技術(shù)要看官方文檔
很多同學(xué)在初學(xué)時(shí)喜歡看一些快速入門的教程蜜自,我覺得這種學(xué)習(xí)習(xí)慣挺好的菩貌,但是建議不要遺漏官方文檔的學(xué)習(xí)。因?yàn)槌鯇W(xué)者很難去鑒定一個(gè)非官方文檔的質(zhì)量重荠,運(yùn)氣不好的話箭阶,還會(huì)被誤導(dǎo)。而且官方文檔最貼近原作者的想法,我們更容易體會(huì)到其設(shè)計(jì)思想仇参。
本文就到此為止啦媳危,本人水平和經(jīng)驗(yàn)有限,如有紕漏冈敛,歡迎指正。如果覺得不錯(cuò)鸣皂,也歡迎點(diǎn)贊抓谴、轉(zhuǎn)發(fā)和留言,你們的支持寞缝,將會(huì)是我持續(xù)寫作的動(dòng)力癌压,謝謝各位的閱讀