我想你每天寫css代碼有時候也會覺得很痛苦:這個布局的css怎么這么難實現(xiàn)!我也經(jīng)常會有這種感覺,一個看似簡單的布局總是要琢磨半天才能實現(xiàn)属铁,偶爾還會出現(xiàn)一些怪異的超出理解的現(xiàn)象。這是因為我們對css只是大概知道個形莽鸿,并沒有看透css的本質。在同事的推薦下我閱讀了張鑫旭老師的《css世界》拾给,才發(fā)現(xiàn)css跟想象中的不太一樣祥得。本文為《css世界》個人總結筆記兔沃,為縮減篇幅丟棄了張老師冗余的小幽默,丟掉了些含金量較低的章節(jié)內(nèi)容啃沪,因為ie已經(jīng)被淘汰出局粘拾,所以有關css兼容性的地方也全部忽略不記,同時對個人覺得不易理解的地方加上了一些自己的理解和驗證创千,所以錯誤之處還望指正缰雇。順便推薦個好用的在線代碼編輯工具,國內(nèi)鏡像站點追驴,方便各位對本文實例進行測試械哟。另外本文會隨著作者對css的更深入理解而逐步更新,希望到最后能夠文如標題展現(xiàn)出真正的css世界殿雪。
小剛老師
基本概念
這些基本概念有些可能不易理解但卻都很重要暇咆,如果看完還是很不理解的話需要自己谷歌或百度,網(wǎng)上關于這些概念的文章不少丙曙。
流
“流”又叫文檔流爸业,是css的一種基本定位和布局機制。流是html的一種抽象概念亏镰,暗喻這種排列布局方式好像水流一樣自然自動扯旷。“流體布局”是html默認的布局機制索抓,如你寫的html不用css钧忽,默認自上而下(塊級元素如div
)從左到右(內(nèi)聯(lián)元素如span
)堆砌的布局方式。
塊級元素和內(nèi)聯(lián)元素
這個大家肯定都知道逼肯。
塊級元素是指單獨撐滿一行的元素耸黑,如div、ul篮幢、li大刊、table、p洲拇、h1
等元素奈揍。這些元素的display值默認是block、table赋续、list-item
等。
內(nèi)聯(lián)元素又叫行內(nèi)元素另患,指只占據(jù)它對應標簽的邊框所包含的空間的元素,這些元素如果父元素寬度足夠則并排在一行顯示的昆箕,如span鸦列、a、em、i、img带射、td
等同规。這些元素的display值默認是inline、inline-block窟社、inline-table券勺、table-cell
等。
實際開發(fā)中灿里,我們經(jīng)常把display
計算值為inline
inline-block
inline-table
table-cell
的元素叫做內(nèi)聯(lián)元素关炼,而把display
計算值為block
的元素叫做塊級元素。
width: auto 和 height: auto
width
钠四、height
的默認值都是auto
盗扒。
對于塊級元素,流體布局之下width: auto
自適應撐滿父元素寬度缀去。這里的撐滿并不同于width: 100%
的固定寬度侣灶,而是像水一樣能夠根據(jù)margin
不同而自適應父元素的寬度。
對于內(nèi)聯(lián)元素缕碎,width: auto
則呈現(xiàn)出包裹性褥影,即由子元素的寬度決定。
無論內(nèi)聯(lián)元素還是塊級元素咏雌,height: auto
都是呈現(xiàn)包裹性凡怎,即高度由子級元素撐開。
注意父元素height: auto
會導致子元素height: 100%
百分比失效赊抖。
css的屬性非常有意思统倒,正常流下,如果塊級元素的width
是個固定值氛雪,margin
是auto
房匆,則margin
會撐滿剩下的空間;如果margin
是固定值,width
是auto
浴鸿,則width
會撐滿剩下的空間井氢。這就是流體布局的根本所在。
外在盒子和內(nèi)在盒子
外在盒子是決定元素排列方式的盒子岳链,即決定盒子具有塊級特性還是內(nèi)聯(lián)特性的盒子花竞。外在盒子負責結構布局。
內(nèi)在盒子是決定元素內(nèi)部一些屬性是否生效的盒子掸哑。內(nèi)在盒子負責內(nèi)容顯示约急。
如 display: inline-table;
外在盒子就是inline
,內(nèi)在盒子就是table
举户。外在盒子決定了元素要像內(nèi)聯(lián)元素一樣并排在一排顯示烤宙,內(nèi)在盒子則決定了元素可以設置寬高、垂直方向的margin等屬性俭嘁。如下圖
右側的table和左側的文字在一行排列(外在盒子inline的表現(xiàn)特征)躺枕,同時有擁有自定義寬度111px(內(nèi)在盒子table可以設置寬高)。
css權重和超越!important
曾經(jīng)有道面試題把我難住了:
// 假設下面樣式都作用于同一個節(jié)點元素`span`供填,判斷下面哪個樣式會生效
body#god div.dad span.son {width: 200px;}
body#god span#test {width: 250px;}
可憐當時做了三年前端的我竟然還不知道css有權重??
css選擇器權重列表如下:
權重值 | 選擇器 |
---|---|
1,0,0,0 | 內(nèi)聯(lián)樣式:style="" |
0,1,0,0 | ID選擇器:#idName{...}
|
0,0,1,0 | 類拐云、偽類、屬性選擇器:.className{...} / :hover{...} / [type="text"] ={...}
|
0,0,0,1 | 標簽近她、偽元素選擇器:div{...} / :after{...}
|
0,0,0,0 | 通用選擇器(*)叉瘩、子選擇器(>)、相鄰選擇器(+)粘捎、同胞選擇器(~) |
以前想當然的以為權重是十進制的薇缅,即十個class選擇器等于一個id選擇器,這是錯誤的攒磨。CSS權重進制在IE6為256泳桦,后來擴大到了65536,而現(xiàn)代瀏覽器則采用更大的數(shù)量娩缰。所以我們可以忽略進制的問題灸撰,從高往低比較權重值。
如果權重是十進制的比較方式拼坎,則十一個class選擇器的權重高于一個ID選擇器浮毯。但經(jīng)測試并非如此:地址。
可以看到十一個class選擇器的樣式并沒有覆蓋一個id選擇器的樣式泰鸡,因為:
當兩個權值進行比較的時候债蓝,是從高到低逐級將等級位上的權重值來進行比較的,而不是 1000個數(shù) + 100個數(shù) + 10個數(shù) + 1個數(shù) 的總和來進行比較的盛龄,換句話說惦蚊,低等級的選擇器個數(shù)再多也不會超過高等級的選擇器的優(yōu)先級的器虾。
正確規(guī)則:
- 先從高等級進行比較讯嫂,高等級相同時蹦锋,再比較低等級的,以此類推欧芽;
- 完全相同的話莉掂,就采用 后者優(yōu)先 原則;
因此上面那道的面試題比較應該是在第二等級id選擇器的比較就結束了:(#god + #test = 0,2,0,0) > (#god = 0,1,0,0)千扔;而上圖種例子中兩個權重分別是:(#test = 0,1,0,0) > (.test....test10 = 0,0,11,0)憎妙,也是在第二等級id選擇器的比較時就結束了。所以以后比較權重曲楚,就先比較id選擇器個數(shù)厘唾,如果id一樣多,再比較class選擇器個數(shù)龙誊。哇抚垃,感覺這可以是一道專坑中文社區(qū)的面試題啊趟大。
在css中鹤树,!important
的權重相當?shù)母摺H绻霈F(xiàn)了!important
逊朽,則不管權重如何都取有!important
的屬性值罕伯。但是寬高有例外情況,由于寬高會被max-width
/min-width
覆蓋叽讳,所以!important
會失效追他。
width: 100px!important;
min-width: 200px;
上面代碼計算之后會被引擎解析成:
width: 200px;
盒模型(盒尺寸)
元素的內(nèi)在盒子是由margin box
、border box
岛蚤、padding box
邑狸、content box
組成的,這四個盒子由外到內(nèi)構成了盒模型灭美。
IE模型: box-sizing: border-box
此模式下推溃,元素的寬度計算為border+padding+content
的寬度總和。
w3c標準模型): box-sizing: content-box
此模式下届腐,元素的寬度計算為content
的寬度铁坎。
由于content-box
在計算寬度的時候不包含border pading
很煩人,而且又是默認值犁苏,業(yè)內(nèi)一般采用以下代碼重置樣式:
:root {
box-sizing: border-box;
}
* {
box-sizing: inherit;
}
內(nèi)聯(lián)盒模型
內(nèi)聯(lián)元素是指外在盒子是內(nèi)聯(lián)盒子的元素硬萍。從表現(xiàn)來說,內(nèi)聯(lián)元素的典型特征就是可以和文字在一行顯示围详。文字也是內(nèi)聯(lián)元素朴乖。圖片祖屏、按鈕、輸入框买羞、下拉框等替換元素也是內(nèi)聯(lián)元素袁勺。內(nèi)聯(lián)盒模型是指內(nèi)聯(lián)元素包含的幾個盒子,理解記憶下面的幾個概念對css的深入學習極其重要畜普。
- 內(nèi)容區(qū)域:本質上是字符盒子期丰。在瀏覽器中,文字選中狀態(tài)的背景色就是內(nèi)容區(qū)域吃挑。
- 內(nèi)聯(lián)盒子:內(nèi)聯(lián)盒子就是指元素的外在盒子是內(nèi)聯(lián)的钝荡,會和其他內(nèi)聯(lián)盒子排成一行。
- 行框盒子:由內(nèi)聯(lián)元素組成的每一行都是一個行框盒子舶衬。如果一行里面沒有內(nèi)聯(lián)元素如一個空的
div
標簽埠通,則不會形成行框盒子。行框盒子由一個個內(nèi)聯(lián)盒子組成逛犹,如果換行端辱,那就是兩個行框盒子。比如一個包含了很多字符的換行的的p
標簽圾浅,每一行都存在一個行框盒子掠手。值得注意的是,如果給元素設置display: inline-block
狸捕,則創(chuàng)建了一個獨立的行框盒子喷鸽。line-height
是作用在行框盒子上的,并最終決定高度灸拍。 - 包含盒子:就是包含塊做祝。多行文字組成一個包含塊,一個包含塊有若干個行框盒子鸡岗。
- 幽靈空白節(jié)點:內(nèi)聯(lián)元素的每個行框盒子前面有一個“空白節(jié)點”混槐,這個“空白節(jié)點”不占據(jù)任何寬度,無法選中獲取轩性,但是又實實在在存在声登,表現(xiàn)就如同文本節(jié)點一樣(本文中大量例子會用字母x模擬幽靈空白節(jié)點)。
替換元素
替換元素是指內(nèi)容可以替換的元素揣苏,實際上就是content box
可以被替換的元素悯嗓。如存在src=""
屬性的<img> <audio> <video> <iframe>
元素和可以輸入文本的<input> <select> <textarea>
元素等。
所有替換元素都是內(nèi)聯(lián)元素卸察,默認display
屬性是inline
或inline-block
(除了input[type="hidden"]
默認display: none;
)脯厨。
替換元素有自己默認的樣式、尺寸(根據(jù)瀏覽器不同而不同)坑质,而且其vertical-align
屬性默認是bottom
(非替換元素默認值是baseline
)。
css的繼承機制
參見css簡單的繼承。
盒模型四大金剛
content
對于非替換元素如div
,其content
就是div內(nèi)部的元素捧书。 而對于替換元素,其content
就是可替換部分的內(nèi)容盟庞。
CSS中的content
屬性主要用于偽元素:before/:after
中,除了做字體庫或少寫個div岂贩,對于一般開發(fā)來說并無卵用茫经。
padding
padding
是四大金剛中最穩(wěn)定的了,少見有什么異常萎津。盡管如此還是有些需要注意的地方:
- 大部分情況下我們會將元素重置為
box-sizing: border-box
,寬高的計算是包含了padding
的抹镊,給人一種padding
也是content box
一部分的感覺锉屈,好像line-height
屬性也作用于padding
上。但實際上垮耳,元素真正的內(nèi)容的寬高只是content box
的寬高颈渊,而line-height
屬性是不作用于padding
的。
-
padding
不可為負值终佛,但是可以為百分比值俊嗽。為百分比時水平和垂直方向的padding
都是相對于父級元素寬度計算的。將一個div
設為padding: 100%
就能得到一個正方形铃彰,padding: 10% 50%
可以得到一個寬高比 5:1 的矩形绍豁。
body {
width: 400px;
}
.box {
padding: 10% 50%;
}
-
padding
配合background-clip
屬性,可以制作一些特殊形狀:
/*三道杠*/
.icon1 {
box-sizing: border-box;
display: inline-block;
width: 12px;
height: 10px;
padding: 2px 0;
border-top: 2px solid currentColor;
border-bottom: 2px solid currentColor;
background: currentColor; /*注意如果此處背景顏色屬性用縮寫的話牙捉,需要放到其他背景屬性的前面竹揍,否則會覆蓋前面的屬性值(此處為background-clip)為默認值*/
background-clip: content-box;
}
/*雙層圓點*/
.icon2 {
display: inline-block;
width: 12px;
height: 12px;
padding: 2px;
border: 2px solid currentColor;
border-radius: 50%;
background-color: currentColor;
background-clip: content-box;
}
預覽如下:(currentColor是css中為數(shù)不多的變量,指當前文字的顏色值邪铲,非常好用)
margin
- 作為外邊距芬位,
margin
屬性并不會參與盒子寬度的計算,但通過設置margin
為負值带到,卻能改變元素水平方向的尺寸:
<div>asdf</div>
<style>
div {
margin: 0 -100px;
}
</style>
此時div
元素的寬度是比父級元素的寬度大200px
的昧碉。但是這種情況只會發(fā)生在元素是流布局的時候,即元素width
是默認的auto
并且可以撐滿一行的時候揽惹。如果元素設定了寬度被饿,或者元素設置了float: left
/ position: absolute
這樣的屬性改變了流體布局,那么margin
為負也無法改變元素的寬度了永丝。
- 塊級元素的垂直方向會發(fā)生
margin
合并锹漱,存在以下三種場景:
- 相鄰兄弟元素之間
margin
合并; - 父元素
margin-top
和子元素margin-top
慕嚷,父元素margin-bottom
和子元素margin-bottom
哥牍; - 空塊級元素自身的
margin-top
和margin-botom
合并毕泌,例子如下。
要阻止margin
合并嗅辣,可以:1. 把元素放到bfc
中撼泛;2. 設置border
或padding
阻隔margin
;3. 用內(nèi)聯(lián)元素(如文字)阻隔澡谭;4. 給父元素設定高度愿题。
-
margin
的百分比值跟padding
一樣,垂直方向的margin
和水平方向上的一樣都是相對于父元素寬度計算的蛙奖。
<div class="box">
<div></div>
</div>
<style>
.box{
overflow: hidden;
background-color: lightblue;
}
.box > div{
margin: 50%;
}
</style>
此時 .box 是一個寬高比 2:1 的矩形潘酗,因為空塊級元素自身的垂直方向的margin
發(fā)生了合并。
這里父元素設置overflow: hidden
是利用 bfc
的特性阻止子元素的margin
和父元素合并雁仲,換成其他 bfc
特性或者設置 1px
的 border
/ padding
都是可以達到效果的仔夺。
-
margin: auto
能在塊級元素設定寬高之后自動填充剩余寬高。margin: auto
自動填充觸發(fā)的前提條件是元素在對應的水平或垂直方向具有自動填充特性攒砖,顯然默認情況下塊級元素的高度是不具備這個條件的缸兔。典型應用是塊級元素水平局中的實現(xiàn):
display: block;
width: 200px;
margin: 0 auto;
auto
的特性是,如果兩側都是auto
吹艇,則兩側均分剩余寬度惰蜜;如果一側margin
是固定的,另一側是auto
受神,則這一側auto
為剩余寬度抛猖。栗子:
這個特性鮮為人知,且很實用路克。
除了水平方向樟结,垂直方向的margin
也能實現(xiàn)垂直居中,但是需要元素在垂直方向具有自動填充特性精算,而這個特性可以利用position
實現(xiàn):
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
width: 200px;
height: 200px;
margin: auto;
border
border
主要作用是做邊框瓢宦。border-style
屬性的值有none/solid/dashed/dotted/double
等,基本看名字就能猜出什么來了:
border-width
屬性的默認值是3px
灰羽,是為了照顧小弟border-style: double
驮履,你懂的。值得注意的是廉嚼,border-color
默認是跟隨字體的顏色玫镐,相當于默認設置了border-color: currentColor
一樣。
border
另一廣受歡迎的功能就是圖形構建怠噪,特別是做應用廣泛的三角形恐似,其原理可看下圖的1-3:
div{
float: left;
margin: 20px;
}
div:nth-child(1){
width: 20px;
height: 20px;
border: 20px solid;
border-color: blue red orange green;
}
div:nth-child(2){
width: 20px;
height: 20px;
border: 20px solid;
border-color: blue transparent transparent transparent;
}
div:nth-child(3){
border: 20px solid;
border-color: blue transparent transparent transparent;
}
div:nth-child(4){
border-style: solid;
border-width: 40px 20px;
border-color: blue transparent transparent transparent;
}
div:nth-child(5){
border-style: solid;
border-width: 40px 20px;
border-color: blue red transparent transparent;
}
其實就是將其他三個邊框的顏色設置透明,并把寬高設為 0 傍念。圖中4-5兩個圖形矫夷,是通過調整邊框寬度和顏色調整三角形的形狀葛闷,把最后一個圖的紅色改為藍色,則是一個直角三角形了双藕。
好基友line-height
和vertical-align
line-height
和vertical-align
是控制元素垂直對齊的兩大屬性淑趾,也是最難理解搞懂的屬性。
字母 x 的角色
在內(nèi)聯(lián)元素的垂直方向對齊中忧陪,基線是最為重要的概念扣泊。line-height
定義的就是兩基線之間的距離,vertical-align
的默認值就是基線嘶摊⊙有罚基線的定義則是字母 x 的下邊緣。
css中有個概念叫x-height
更卒,指的是小寫字母 x 的高度等孵。vertical-align: middle
對齊的就是基線往上1/2x-height
高度的地方,可以理解為近似字母 x 的交叉點蹂空。
css中除了px/em/rem
等,還有個單位是ex
果录。指的就是小寫字母x的高度上枕,即x-height
。用處不大弱恒,不再介紹辨萍。
line-height
-
line-height
各類屬性值
normal
: 默認值normal
其實是類型為數(shù)值的變量,根據(jù)瀏覽器和字體'font-family'不同而不同返弹,一般約為 1.2 锈玉。
數(shù)值和百分比:最終會被計算為帶單位的值,具體計算方法就是乘以字體大小font-size
义起。
長度值:就是100px
這樣帶單位的值拉背。
這幾類值的繼承特性不同:line-height
是數(shù)值的元素的子元素繼承的就是這個數(shù)值,百分比/長度值繼承的都是計算后得出的帶單位的值(px)默终。
-
line-height
的作用:
line-height
屬性用于設置多行元素的空間量椅棺,如多行文本的間距。
對塊級元素來說齐蔽,line-height
決定了行框盒子的最小高度两疚。注意是行框盒子的最小高度,而不是塊級元素的實際高度含滴。(圖中兩個div
行高一樣诱渤,div.one
的背景色區(qū)域就是行框盒子的高度,而 div.two
的背景區(qū)域則是實際高度谈况,其行框盒子高度和 div.one
是一樣的勺美。)
對于非替代的 inline 元素递胧,它用于計算行框盒子的高度。此時內(nèi)聯(lián)元素的行框盒子的高度完全由line-height
決定励烦,不受其他任何屬性的影響谓着。
-
line-height
實現(xiàn)垂直居中的本質:行距
行距是指一行文本和相鄰文本之間的距離。行距 = line-height
— font-size
坛掠。行距具有上下等分的機制:意思就是文字上下的行距是一樣的赊锚,各占一半,這也是line-height
能讓內(nèi)聯(lián)元素垂直居中的原因屉栓。下圖中字母x上下行距各占一半舷蒲,共同撐起了div
。
下圖中和上圖唯一不同之處就是多了個display: inline-block
的span
元素友多,但是此處的span
元素并沒有影響div
元素的高度牲平,而只是靠著vertical-align: middle
屬性將自身中心點對齊了字母x的交叉點實現(xiàn)垂直居中而已。div
元素的高度仍然和上圖一模一樣域滥,由字母x和行距共同撐起纵柿。此時如果刪除字母x,div
的高度不變启绰,因為span
元素的行框盒子前會產(chǎn)生幽靈空白節(jié)點昂儒,而幽靈空白節(jié)點+行高也能撐起div
。
- 內(nèi)聯(lián)元素的大值特性
<div class="box">
<span>asdf</span>
</div>
樣式1:此時 .box 高度是多少委可?
.box {
line-height: 100px;
background: lightgreen;
}
.box span {
line-height: 30px;
}
樣式2:此時 .box 高度是多少渊跋?
.box {
line-height: 30px;
background: lightgreen;
}
.box span {
line-height: 100px;
}
先說結論:無論內(nèi)聯(lián)元素的line-height
如何設置,最終父元素的高度都是數(shù)值大的那個line-height
決定的着倾。
樣式1中拾酝,span
元素的行框盒子前存在一個幽靈空白節(jié)點,而這個幽靈空白節(jié)點的行高是100px卡者;樣式2中蒿囤,幽靈空白節(jié)點的行高是30px,但是這時span元素的行高是100px虎眨。兩種情況其實一樣蟋软,取大值而已。
vertical-align
-
vertical-align
的屬性值
線類: 如baseline(默認值)
top
middle
bottom
(baseline
使元素的基線與父元素的基線對齊嗽桩,middle
使元素的中部與父元素的基線往上x-height
的一半對齊岳守。top
bottom
使元素及其后代元素的底部與整行或整塊的底部對齊。)
文本類: text-top
text-bottom
(使元素的頂部與父元素的字體頂部對齊碌冶。)
上標下標: sub
super
(使元素的基線與父元素的下標基線對齊湿痢。)
數(shù)值: 20px
2em
(默認值baseline
相當于數(shù)值的 0 。使元素的基線對齊到父元素的基線之上的給定長度,數(shù)值正值是基線往上偏移譬重,負值是往下偏移拒逮,借此可以實現(xiàn)元素垂直方向精確對齊。)
百分比: 20%
(使元素的基線對齊到父元素的基線之上的給定百分比臀规,該百分比是line-height屬性的百分比滩援。)
-
vertical-align
的作用前提
vertical-align屬性起作用的前提必須是作用在內(nèi)聯(lián)元素上。 即display
計算值為inline
inline-block
inline-table
table-cell
的元素塔嬉。所以如果元素設置了float: left
或者position: absolute
玩徊,則其vertical-align
屬性不能生效,因為此時元素的display
計算值為block
了谨究。
- 好基友
line-height
恩袱、vertical-align
和第三者幽靈空白節(jié)點的愛恨情仇
有時候會遇見下面這樣高度和設置不一致的情況:
div
的實際高度比設定的行高大了,為什么呢胶哲?
內(nèi)聯(lián)元素的默認對齊方式是baseline
畔塔,所以此時此時span
元素的基線是和父元素的基線相對齊的,而此時父元素的基線在哪呢鸯屿?
父元素的基線其實就是行框盒子前的幽靈空白節(jié)點的基線澈吨。把幽靈空白節(jié)點具象化為字母x
可能容易理解些:
由于div
行高是30px
,所以字母x
和span
元素的高度都是30px
寄摆。但是字母x的font-size
較小棚辽,span
元素的font-size
較大,而行高一樣的情況下font-size
越大基線的位置越偏下冰肴,所以兩者的基線不在同一水平線上。如下圖左邊部分:
由于內(nèi)聯(lián)元素默認基線對齊榔组,所以字母x
和span
元素發(fā)生了位移以使基線對齊熙尉,導致div
高度變大。而此時字母x
的半行距比span
元素的半行距大搓扯,大出的部分就是div
的高度增加的部分检痰。
-
display: inline-block
基線的不同之處
先看例子,圖中span
元素設置了display: inline-block
和寬高锨推,從而撐起了父元素div
的高度铅歼,但span
本身并無margin
屬性,那為什么底部和div
下邊緣之間會有空隙呢换可?地址
這就要說到inline-block
的不同之處了椎椰。一個設置了display: inline-block
的元素:
- 如果元素內(nèi)部沒有內(nèi)聯(lián)元素,則該元素基線就是該元素下邊緣沾鳄;
- 如果元素設置了
overflow
為hidden auto scroll
慨飘,則其基線就是該元素下邊緣; - 如果元素內(nèi)部還有內(nèi)聯(lián)元素,則其基線就是內(nèi)部最后一行內(nèi)聯(lián)元素的基線瓤的。
知道了這點休弃,那么再回到上面的例子:
原來是第三者幽靈空白節(jié)點搞的鬼。此時span
的行框盒子前圈膏,還存在一個幽靈空白節(jié)點塔猾。由于span
元素默認基線對齊,所以span
元素的基線也就是其下邊緣是和幽靈空白節(jié)點的基線對齊的稽坤。從而導致幽靈空白節(jié)點基線下面的半行距撐高了div
元素丈甸,造成空隙。如下圖:
如果span
元素中存在內(nèi)聯(lián)元素呢慎皱?
可以看到老虫,此時span
元素下邊緣的空隙沒了,因為此時span
元素的基線是內(nèi)部最后一行內(nèi)聯(lián)元素的基線茫多。
值得一提的是祈匙,由于替換元素內(nèi)部不可能再有別的元素,所以其基線位置永遠位于下邊緣天揖。
- 解決問題
間隙產(chǎn)生本質上是由基線對齊引發(fā)的錯位造成的夺欲,源頭上是vertical-align
和line-height
共同造成的,所以要想解決這個問題今膊,只要直接或間接改造兩個屬性中的一個就行了:
- 給元素設置塊狀化
display: block
使vertical-align
屬性失效些阅; - 嘗試不同的
vertical-align
值如bottom/middle/top
; - 直接修改
line-height
值斑唬; - 如果
line-height
為相對值如1.4
市埋,設置font-size: 0
間接改變line-height
。
- 彈框dialog
下面是張鑫旭大佬推薦的利用vertical-align
實現(xiàn)的水平垂直居中彈框恕刘,能夠理解的話就說明你已經(jīng)完全掌握了好基友和第三者的關系了缤谎。
<div class="container">
<div class="dialog">自適應彈出層</div>
</div>
<style>
.container{
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
background-color: rgba(0, 0, 0, .15);
text-align: center;
font-size: 0;
white-space: nowrap;
overflow: auto;
}
.container:after{
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
.dialog{
display: inline-block;
width: 400px;
height: 400px;
vertical-align: middle;
text-align: left;
font-size: 14px;
white-space: normal;
background: white;
}
</style>
流的破壞
現(xiàn)在UI框架橫行的年代,我們的css寫的越來越少了褐着。這對于很多老鳥來說是件好事坷澡,但是對于初入前端的小白卻未必。因為寫的少了含蓉,就少了很多練手和總結的機會频敛,對于很多樣式理解就不透徹。本章介紹的float
馅扣、position
和BFC
對于前端頁面布局非常重要斟赚,希望諸位看官們靜下心來仔細研讀。
float
屬性的特性
float
屬性應該是css世界最令人意外的屬性了岂嗓,倒不是因為他的表現(xiàn)汁展,而是他的設計初衷竟然只是為了實現(xiàn)“文字環(huán)繞圖片”的效果。只不過因為float
屬性的一些特性,才導致其被到處使用以致于產(chǎn)生了諸多不利于維護的頁面食绿。 下面看看float
屬性的特性:
- 包裹性:即此時元素
width
會像height
一樣由子元素決定侈咕,而不是默認撐滿父元素。 - 塊狀化并格式化上下文:這個就是后面會講的BFC特性器紧。塊狀是指元素設置
float: left
之后耀销,其display
的計算值就成了block
。格式化上下文是指會創(chuàng)建一個BFC铲汪,這個后面會講熊尉。 - 沒有任何
margin
合并; - 脫離文檔流:
float
設計的初衷就是為了“文字環(huán)繞”效果掌腰,為了讓文字環(huán)繞圖片狰住,就需要具備兩個條件。第一是元素高度坍塌齿梁,第二是行框盒子不可與浮動元素重疊催植。而元素高度坍塌就導致元素后面的非浮動塊狀元素會和其重疊,于是他就像脫離文檔流了勺择。
前三個特性都是正能量滿滿冒窍,但是最后一個特性卻給我們開發(fā)者帶來了很多麻煩佑菩,需要用到clear
來清除浮動。
clear
的作用和不足
大家都知道clear: both
可以清除前面浮動元素的浮動竿拆,但實際上埠戳,他并不是真的清除了浮動湿镀。
clear
的定義是:元素盒子的邊不能與前面的浮動元素相鄰诫钓。也就是雖然浮動元素高度坍塌幔睬,但是設置了clear: both
的元素卻將其高度視為仍然占據(jù)位置。
clear
只能作用于塊級元素旧噪,并且其并不能解決后面元素可能發(fā)生的文字環(huán)繞問題芥备。
BFC:塊級格式化上下文
- 概念
BFC是一個獨立的渲染區(qū)域,只有Block-level box
參與舌菜, 它規(guī)定了內(nèi)部的Block-level Box
如何布局,并且與這個區(qū)域外部毫不相干亦镶。 BFC 就好像一個結界日月,結界里面的東西不能影響外面的布局,也就是說缤骨,BFC的子元素再翻江倒海爱咬,都不會影響外面的元素。 所以:
- BFC本身不會發(fā)生
margin
重疊绊起。 - BFC可以徹底解決子元素浮動帶來的的高度坍塌和文字環(huán)繞問題精拟。
- BFC的創(chuàng)建方法
- html根元素
- 浮動元素,float不是none就行
- 絕對定位元素,absolute和fixed
- display不是block的塊(inline-block蜂绎、table-cell栅表、table-caption)
- overflow 值不為 visible 的元素(hidden、auto师枣、scroll)
- display為flex怪瓶、grid、flow-root的元素(flow-root為專門設置BFC的屬性值)
BFC包含創(chuàng)建該上下文元素的所有子元素践美,但不包括創(chuàng)建了新BFC的子元素的內(nèi)部元素洗贰。
- 特性
- 內(nèi)部的盒會在垂直方向一個接一個排列(可以看作BFC中有一個的常規(guī)流);
- Box垂直方向的距離由
margin
決定陨倡。屬于同一個BFC的兩個相鄰Box的margin
會發(fā)生重疊敛滋; - 每一個盒子的左外邊距應該和包含塊的左邊緣相接觸。即使存在浮動也是如此兴革,除非子盒子形成了一個新的BFC绎晃。
- BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素帖旨,反之亦然箕昭;
- 計算BFC的高度時,考慮BFC所包含的所有元素解阅,連浮動元素也參與計算落竹;
- BFC的區(qū)域不會與
float box
重疊;
乍一看還挺多的货抄,但真正要注意并用心理解的只有 3 4 6 述召。
特性 1 中內(nèi)部的盒是指塊級盒。因為<html>
根元素也是BFC蟹地,所以我們平常寫的div p
都是獨自占一行积暖。
特性 2 <html>
是BFC,所以里面的元素垂直方向的margin
會發(fā)生折疊怪与。但是夺刑,直接子孫元素與該BFC上下邊界margin
不能折疊,保證了BFC內(nèi)部的元素不會影響外部的元素分别。兩個上下相鄰的BFC之間折不折疊要看具體情況遍愿,如display: inline-block
float: left
不會折疊,而overflow: hidden
則會折疊耘斩。
特性 3 完全解讀:
In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box's line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).
網(wǎng)上很多翻譯成“每個元素的margin box
的左邊沼填, 與包含塊border box
的左邊相接觸”的,這樣的翻譯是不準確甚至錯誤的括授,曾給我造成莫大的困惑和迷茫(這翻譯太坑爹了一度讓我懷疑人生)坞笙。正確的翻譯是“每一個盒子的左外邊距應該和包含塊的左邊緣相接觸”岩饼。
第一,包含塊未必就是父級元素薛夜。對于position: absolute
來說籍茧,包含塊是指第一個positoin
不為static
的祖先元素。
第二却邓,BFC中的盒子應該與其自身的包含塊相接觸硕糊,而非與BFC盒子本身相接觸。
第三腊徙,BFC中的盒子是與其包含塊的 left edge
相接觸简十,而不是包含塊的 left-border
相接觸。left edge
正確的翻譯為左邊緣撬腾。左邊緣可能是content box
的左邊緣(非絕對定位如position: relative
float: left
)螟蝙,也可能是padding box
的左邊緣(如絕對定位position: absolute
position: fixed
)。
理解了上面三點民傻,其實特性 3 就是普通的流布局和定位布局默認貼著“左側”思想的總結胰默。
如圖,aside
元素的margin box
的左邊距和BFC元素的左邊緣相接觸漓踢。并且由于float box
高度坍塌牵署,main
占據(jù)了body
全部空間并且和包含塊BFC盒子左邊緣相接觸(特性3“即使存在浮動也是如此”)。
特性 4 正是BFC存在的意義喧半。它規(guī)定了BFC子元素無論margin-top: -10000px
float: left
等都不會影響到BFC外部的元素的布局奴迅。所以BFC是最好的清除浮動的方式,連浮動的文字環(huán)繞問題都能解決挺据。
特性 5 BFC計算高度時包含浮動元素的高度取具。可以利用BFC此特性解決浮動元素高度坍塌的問題扁耐。
特性 6 實現(xiàn)自適應兩欄布局暇检。此時main
寬度是自適應的。
除了 BFC 婉称,還有 IFC GFC FFC 等布局块仆,了解即可,想看點 這里王暗。
絕對定位 position: absolute
- 定義
和浮動元素一樣榨乎,絕對定位也具有塊狀化、BFC瘫筐、包裹性、脫離文檔流铐姚、沒有margin
合并的特性策肝。
但和浮動不同的是肛捍,絕對定位是完全的脫離文檔流。大家還記得浮動產(chǎn)生的目的就是為了實現(xiàn)文字環(huán)繞效果之众,所以浮動元素雖然脫離了文檔流拙毫,但是后面的文字還是會環(huán)繞在浮動元素周圍。而絕對定位一但產(chǎn)生棺禾,就不會再對周圍元素產(chǎn)生任何影響缀蹄。
而且兩者包含塊不同,浮動元素包含塊只能是父級元素膘婶,絕對定位的包含塊則是距離最近的position
不為static
的祖先元素缺前。
- 默認最大寬度為包含塊的寬度
這個特性看起來很正常,因為正常的元素默認最大寬度都是包含塊的寬度悬襟。
由于這個特性衅码,如果包含塊的寬度很小,會出現(xiàn)一柱擎天的現(xiàn)象脊岳。解決方法也很簡單逝段,加個
white-space: nowrap
讓文本不換行就行了:地址- 無依賴絕對定位
大多數(shù)用到絕對定位的時候,都是存在包含塊和left/top
等方向屬性的割捅。但其實position: absolute
是非常獨立的css屬性奶躯,其樣式和行為表現(xiàn)不依賴任何css屬性就可以完成。
可以看出亿驾,無依賴的position: absolute
元素定位的位置和其本身無定位屬性時候的位置和display
的值有關嘹黔。如果元素在沒有position
的情況下是內(nèi)聯(lián)元素,則和內(nèi)聯(lián)元素在同一行顯示颊乘;如果元素在沒有position
屬性的情況下是塊級元素参淹,則換行顯示。
無依賴絕對定位的實用性雖然還行乏悄,但是其功能卻完全可以用left/top
實現(xiàn)浙值。所以了解即可,如果有興趣可以自行嘗試檩小。
- 絕對定位和
overflow: hidden
其實一句話就可以表示兩者之間的關系:當overflow: hidden
元素在絕對定位元素和其包含塊之間的時候开呐,絕對定位元素不會被剪裁。
以下兩種絕對定位元素不會被剪裁:
<div style="overflow: hidden;">
<img src="big.jpg" style="position: absolute;">
</div>
<div style="position: relative;">
<div style="overflow: hidden;">
<img src="big.jpg" style="position: absolute;">
</div>
</div>
以下兩種絕對定位元素會被剪裁:
<div style="overflow: hidden; position: relative;">
<img src="big.jpg" style="position: absolute;">
</div>
<div style="overflow: hidden;">
<div style="position: relative;">
<img src="big.jpg" style="position: absolute;">
</div>
</div>
-
position: absolute
的流體特性
當絕對定位元素的水平方向(left/right
)或垂直方向(top/bottom
)的兩個定位屬性同時存在的時候规求,絕對元素在該方向上便具有了流體特性筐付。此時的width/height
屬性具有自動撐滿的特性,和一個正常流的div
元素的width
屬性別無二致阻肿。如圖瓦戚,設置了固定margin
值的元素,寬高auto
能夠自動適應剩余空間:
同樣的丛塌,設置了固定寬高的元素较解,如果margin: auto
畜疾,則margin
平分剩余空間導致垂直水平居中:
固定定位 position: fixed
position: fixed
是相對于屏幕視口的位置來指定元素位置,祖先元素設置 position: relative
并不會對其產(chǎn)生影響印衔。
position: fixed
只有一個要注意的點啡捶,那就是當元素祖先的 transform
屬性非 none
時,容器由視口改為該祖先:地址
粘性定位 position: sticky
#one { position: sticky; top: 10px; }
復制代碼
在 viewport 視口滾動到元素 top 距離小于 10px 之前奸焙,元素為相對定位瞎暑。之后,元素將固定在與頂部距離 10px 的位置与帆,直到 viewport 視口回滾到閾值以下了赌。
利用粘性定位實現(xiàn)固定字母表頭部元素:地址
需注意當 position: sticky
的父元素的 overflow
屬性設置了默認值 visible
以外的值時,position: sticky
將失效鲤桥。
position: sticky
除了不兼容 ie 瀏覽器揍拆,其他還好。
層疊規(guī)則
層疊規(guī)則是指當網(wǎng)頁中的元素發(fā)生層疊時侯的遵循的規(guī)則茶凳。
層疊上下文
層疊上下文好像是一個結界嫂拴,層疊上下文內(nèi)的元素如果跟層疊上下文外的元素發(fā)生層疊,則比較該層疊上下文和外部元素的層疊上下文的層疊水平高低贮喧。
創(chuàng)建一個層疊上下文的方法就是給position
值為relative/aboslute/fixed
的元素設置z-index
不為auto
的值筒狠。
層疊上下文內(nèi)元素的層疊水平如下圖:
- 最底層
border/background
是當前層疊上下文元素的邊框和背景色(注意不包括文字,文字相當于內(nèi)聯(lián)盒子)箱沦。z-index
為負值的元素在其之上辩恼。
如下圖所示,雖然 .dad
元素設置了 position: relative
谓形,但是由于元素默認為 z-index: auto
灶伊,并沒有創(chuàng)建層疊上下文,此時其就是一個普通的塊級盒子寒跳。所以設置了z-index: -1
的.son
元素跑到了爸爸身后看不見了聘萨。
而由于.mom
設置了z-index: 0
,創(chuàng)建出了一個層疊上下文童太,所以.son
元素就算設置了z-index: -1
也跑不出老媽的視線米辐。地址
-
當塊級元素和內(nèi)聯(lián)元素發(fā)生層疊,內(nèi)聯(lián)元素居于塊級元素之上书释。如下圖:地址
-
普通定位元素層疊水平在普通元素之上翘贮。普通定位元素是指
z-index
為auto
的定位元素。下圖span
就是普通定位元素:地址
CSS3新增層疊上下文
CSS3帶來了很多新屬性爆惧,其中很不惹人注意的一點就是增加了很多會自動創(chuàng)建層疊上下文的屬性:
- 元素的
opacity
值不為1
狸页,也就是透明元素; - 元素的
transform
值不為none
扯再; - 元素的
filter
值不為none
芍耘; - 元素的設置
-webkit-overflow-scrolling: touch
腹侣; -
z-index
不為auto
的彈性盒子的子元素; - 元素的
isolation
值為isolate
齿穗; - 元素的
mix-blend-mode
值不為normal
; - 元素的
will-change
值為opacity/transform/filter/isolation/mix-blend-mode
中的一個饺律。
這些屬性大都不支持z-index
窃页,所以他們都默認z-index: auto
,跟普通定位元素層疊水平一樣复濒,所以如果發(fā)生層疊會后來居上:地址
但是彈性盒子display: flex
不同脖卖,彈性盒子的子元素支持設置z-index
,且設置了數(shù)值的z-index
也會自動創(chuàng)建層疊上下文巧颈。如下圖畦木,可以看到設置了z-index: 0
的元素層疊水平更高。地址
文本控制
以下css屬性為文本相關砸泛。
::first-letter
應用實例
::first-letter
選中首個字符:地址
text-transform
應用
假設有個輸入框只能輸入大寫字母十籍,那么如下設置,輸入小寫字母出現(xiàn)的卻是大寫字母唇礁,可用于身份證輸入框或驗證碼輸入框等:
input {
text-transform: uppercase;
}
word-spacing
空格間隙
不要被表面意思誤導勾栗,word-spacing
指的是字符“空格”的間隙。如果一段文字中沒有空格盏筐,則該屬性無效围俘。下面代碼設定空格間隙是20px
,也就是說空格現(xiàn)在占據(jù)的寬度是原有的空格寬度+20px
的寬度:
<p>我有空 格琢融,我該死......</p>
<style>
p {
word-spacing: 20px;
}
</style>
white-space
空白處理
我們都知道如果在html
中輸入多個空白符界牡,默認會被當成一個空白符處理,實際上就是這個屬性控制的:地址
- normal:合并空白符和換行符漾抬;
- nowrap:合并空白符宿亡,但不許換行;
- pre:不合并空白符奋蔚,并且只在有換行符的地方換行她混;
-
pre-wrap:不合并空白符,允許換行符換行和文本自動換行泊碑;
text-align: justify
(本文重點例子!)
text-align: justify
為兩端對齊(對尾行無效且子元素之間必須有空格或換行符)坤按。除了實現(xiàn)文字的兩端對齊,還能用來做一些兩端對齊的布局馒过。下面介紹個兩端對齊布局的實例:地址
由于text-align: justify
最后一行是左對齊臭脓,所以利用了三個空的i
標簽模擬最后一行。雖然實現(xiàn)了兩端對齊腹忽,但是最后一行卻出現(xiàn)間隙来累。根據(jù)之前的經(jīng)驗應該是vertical-align
和line-height
搞的鬼砚作,我們給i
標簽加上outline
并用字母 x 模擬幽靈空白節(jié)點,現(xiàn)形:地址
上圖分析:首先第一個i
標簽基線與第二行的span
標簽中的數(shù)字的基線對其嘹锁,所以其位置在中間葫录。其次最后一行的i
標簽基線對齊幽靈空白節(jié)點字母x的基線,沒有錯位领猾,所以此時最后一行的間隙高度就是字母x的高度米同。所以很容易想到把幽靈空白節(jié)點的行高設為 0 來解決問題:地址
然而間隙雖然縮小了,但是還是存在摔竿。此時由于行高為 0 面粮,幽靈空白節(jié)點也就是字母x在頁面中占用的真實位置其實是紅線所示。也就是說雖然字母 x 還顯示在頁面上继低,但是其真實高度已經(jīng)為0熬苍,此時其中線、上邊緣線袁翁、下邊緣線合一柴底,都在紅線位置,其真實位置自然也就在紅線位置梦裂。然而其基線卻不會改變似枕,在字母 x 下邊緣。
此時i
標簽的基線發(fā)生錯位年柠,位移到下面與幽靈空白節(jié)點基線對齊凿歼,導致產(chǎn)生了間隙。
所以只需要再改變i
標簽的對齊方式冗恨,就能徹底清除間隙:地址
此時i
標簽的基線對齊其幽靈空白節(jié)點的下邊緣線答憔,沒有了錯位,也就沒有了間隙掀抹。
如果改為vertical-align: top
是一樣的虐拓,因為合一了。但是vertical-align: middle
卻不行傲武,因為此middle
的位置是基線往上 1/2 個e-height
的地方蓉驹。
好吧本例結束了,沒想到解釋起來這么復雜揪利。雖然當下兩端對齊布局使用這種方法已經(jīng)過時了(沒 flex 實現(xiàn)起來簡單态兴,更沒 grid 實現(xiàn)好),但是好好學習這個方法能加深對vertical-align
和line-height
的理解疟位。
元素的顯示與隱藏
元素的顯示隱藏方法很多瞻润,不同方法的在不同的場景下頁面效果不一,對頁面的性能也有不同的影響。
元素隱藏方法總結:
- 如果希望元素不可見绍撞、不占據(jù)空間正勒、資源會加載、DOM 可訪問:
display: none
傻铣; - 如果希望元素不可見章贞、不能點擊、但占據(jù)空間非洲、資源會加載阱驾,可以使用:
visibility: hidden
; - 如果希望元素不可見怪蔑、不占據(jù)空間、顯隱時可以又
transition
淡入淡出效果:地址
div{
position: absolute;
visibility: hidden;
opacity: 0;
transition: opacity .5s linear;
background: cyan;
}
div.active{
visibility: visible;
opacity: 1;
}
這里使用visibility: hidden
而不是display: none
丧荐,是因為display: none
會影響css3的transition
過渡效果缆瓣。 但是display: none
并不會影響cssanimation
動畫的效果。
- 如果希望元素不可見虹统、可以點擊弓坞、占據(jù)空間,可以使用:
opacity: 0
车荔; - 如果希望元素不可見渡冻、可以點擊、不占據(jù)空間忧便,可以使用:
opacity: 0; position: absolute;
族吻; - 如果希望元素不可見、不能點擊珠增、占據(jù)空間超歌,可以使用:
position: relative; z-index: -1;
; - 如果希望元素不可見蒂教、不能點擊巍举、不占據(jù)空間伏钠,可以使用:
position: absolute ; z-index: -1;
管宵;
display: none
與visibility: hidden
的區(qū)別
-
display: none
的元素不占據(jù)任何空間,visibility: hidden
的元素空間保留区匣; -
display: none
會影響css3的transition
過渡效果梦皮,visibility: hidden
不會炭分; -
display: none
隱藏產(chǎn)生重繪 ( repaint ) 和回流 ( relfow ),visibility: hidden
只會觸發(fā)重繪届氢;(回流重繪知識點參考:真正理解重繪和回流) - 株連性:
display: none
的節(jié)點和子孫節(jié)點元素全都不可見欠窒,visibility: hidden
的節(jié)點的子孫節(jié)點元素可以設置visibility: visible
顯示。visibility: hidden
屬性值具有繼承性,所以子孫元素默認繼承了hidden
而隱藏岖妄,但是當子孫元素重置為visibility: visible
就不會被隱藏型将。
如果面試問到這個問題,回答出來這四點應該是極好的荐虐。
彈性布局
彈性布局是指display: flex
或display: inline-flex
的布局七兜。注意,設為彈性布局以后福扬,子元素的float腕铸、clear、vertical-align
屬性都會失效铛碑。參見阮一峰大佬的 Flex 布局教程狠裹。
主要屬性應用如下:
彈性布局實現(xiàn)兩端對齊尾行左對齊:地址
可以看到 .container
容器中加了很多 i
空元素,這是為了模擬項目占位汽烦,也是彈性布局實現(xiàn)兩端對齊的唯一不足之處~
網(wǎng)格布局
網(wǎng)格布局是目前最強大的 CSS 布局方案涛菠。這里總結了用 Grid 實現(xiàn)的常用 css 布局:Grid網(wǎng)格布局實例
更新說明
- 更新了
css權重和超越!important
章節(jié)中權重部分的錯誤知識;(2019.10.16) - 更新了
彈性布局實現(xiàn)兩端對齊尾行左對齊
實例撇吞;(2019.10.16) - 更新了
text-align: justify
鏈接中實例的顯示俗冻,固定了容器寬度;(2019.10.16) - 新增了
固定定位 position: fixed
牍颈;(2019.11.7) - 新增了
粘性定位 position: sticky
迄薄;(2019.11.7) - 新增了
默認最大寬度為包含塊的寬度
;(2020.3.27) - 更新了
BFC的創(chuàng)建方法
煮岁;(2020.4.23)