因爲從工做到如今,個人主要工做都是寫JavaScript,幾乎沒怎麼碰CSS,一般都是別人寫好界面,而後我來開發JavaScript邏輯代碼,這致使了嚴重的偏科,CSS弱得很,因此我決定要從新學習CSS,從打好CSS2的基礎開始。最近我開始在看一本關於CSS的書,這本書叫《CSS世界》,是張鑫旭這個CSS大神寫的,質量十分有保障。css
這本書幾乎徹底顛覆了我對於CSS的認知,幾乎等於重塑個人CSS世界觀。html
子曰:學而不思則罔,思而不學則殆。
因此我決定把從這本書學習到的知識結合我看到的一些文檔來總結一下,以便之後複習使用,因此文章中的看法也有多是錯的,不追求徹底正確,而是但願可以做爲方法論來指導以後的CSS開發。若有錯誤,請諸君指正。前端
浮動的本質就是爲了實現文字環繞效果 ——《CSS世界》第六章 流的破壞和保護
熟悉張鑫旭老師的人,應該在他的博客和一些視頻教程中都有聽到上面那句話,可能和我同樣,咋一看以爲懂,而後就不覺得然就過去了,而後使用在float
的時候仍是錯誤百出。瀏覽器
撇開咱們是前端開發者這個身份,讓咱們做爲一個普通用戶的角度來思考有哪些場景咱們會用到文字環繞效果。相信不少人都是使用過Word
這個軟件,在咱們編輯圖文信息的時候,但願文字能夠圍繞圖片來排列,也就是文字環繞,也就是從圖1變爲圖2:svg
<center>圖1</center>佈局
<center>圖2</center>學習
仍是同樣,讓咱們做爲一個普通用戶來思考如何實現這一效果。爲了方便,我在這裏定義一些詞彙,將文本、段落稱之爲跟隨內容
,將圖片等須要被環繞的稱之爲目標元素
。
首先而後咱們將這二者簡化一下,分紅兩個區塊,如圖:spa
而所謂的環繞,那就是把兩個區塊重疊在一塊兒,目標元素
懸浮於重疊區上面,並且重疊區不能有跟隨內容
的內容,如圖:翻譯
因此要使得跟隨內容
可以環繞目標元素
咱們須要作到如下步驟:設計
跟隨內容
的頂部可以上升到與目標元素
頂部同一水平線上;跟隨內容
與目標元素
的重疊區域不能有文字,不重疊區域按照原來的排版方式。浮動最初是爲了實現文字環繞效果,通過上面的討論咱們意識到了須要讓浮動元素和跟隨元素的頂部上升到同一水平線上。而在文檔流中,若是浮動元素和跟隨元素都是Div元素,它們兩在默認狀況下都將佔據一行。因此咱們要讓浮動元素脫離文檔流,這個時候跟隨元素才能根據文檔流的要求進行上移,從而達到視覺上的重疊效果。
而因爲浮動元素脫離了文檔流,若是父元素沒有指定高度或者其餘元素撐起,也就出現了所謂的浮動元素的父元素高度塌陷。
在進行原理分析前,讓咱們先來看一段代碼,並想象它的渲染結果
<style> .box { border:1px solid red; width: 200px; margin-left:50px; } .text { background-color:gray; color:white; } .float { float:left; color:blue; } </style> <div class='box'> 我就是 <span class='text'>一段文本<em class='float'>浮動</em></span> </div>
此時,你腦海裏想象的結果可能以下圖:
但實際運行效果倒是這樣的:
爲何會出現這種狀況呢?讓咱們從CSS的標準中找尋答案。W3C的CSS標準文檔關於浮動的描述中有這樣一段話:
A floated box is shifted to the left or right until its outer edge touches the
containing block
edge or the outer edge of another float
翻譯成中文就是:
一個浮動盒會向左或向右移動,直到其外邊界捱到
包含塊
邊界或者另外一個浮動盒的外邊界。
OK,先撇開有多個浮動元素的狀況,讓咱們只考慮一個浮動元素的狀況。注意到上述引用文本中的高亮詞沒有?包含塊(containing block)
,沒錯,之因此剛纔咱們對代碼運行的渲染效果的想象與實際瀏覽器運行的效果產生誤差,就是由於咱們沒有意識到包含塊(containing block)
,或者識別錯了浮動元素的包含塊
,而這個包含塊
就是元素浮動的參考位置!
在W3C的CSS標準文檔中關於包含塊的描述中有這樣一段話:
The position and size of an element's box(es) are sometimes calculated relative to a certain rectangle,called the containing block of the element
翻譯成中文就是:
元素(生成的)盒的位置和大小有時是根據一個特定矩形計算的,叫作該元素的包含塊(containing block)
關於如何肯定一個元素的包含塊,標準也給出了定義,因爲英文的較長,閱讀起來比較吃力,在此我放一段中文的定義:
- 根元素所在的包含塊是一個被稱爲初始包含塊的矩形。對於連續媒體,尺寸取自視口的尺寸,而且被固定在畫布開始的位置;對於分頁媒體就是頁區(page area)。初始包含塊的'direction'屬性與根元素的相同
- 對於其它元素,若是該元素的position是'relative'或者'static',包含塊由其最近的塊容器祖先盒的內容邊界(
the content edge
)造成
- 若是元素具備'position: fixed',包含塊由連續媒體的視口或者分頁媒體的頁區創建
- 若是元素具備'position: absolute',包含塊由最近的'position'爲'absolute','relative'或者'fixed'的祖先創建,按照以下方式:
- 若是該祖先是一個行內元素,包含塊就是環繞着爲該元素生成的第一個和最後一個行內盒的內邊距框的邊界框(bounding box)。在CSS 2.1中,若是該行內元素被跨行分割了,那麼包含塊是未定義的
- 不然,包含塊由該祖先的內邊距邊界造成
若是沒有這樣的祖先,包含塊就是初始包含塊
根據上面關於包含塊的定義,咱們能夠發現.float
元素符合第2條,那麼它的包容塊就是.box
這個div
的內容邊界
,注意是內容邊界(the content edge
),而不是整個盒子,因此不包含padding、border、margin。
讓咱們先來看一張關於盒模型圖:
W3C的CSS規範關於content edge
的定義是:
The content edge surrounds the rectangle given by the width and height of the box, which often depend on the element's rendered content The four content edges define the box's content box.
翻譯成中文就是:
內容邊界環繞着盒的width和height指出的矩形,一般取決於元素的呈現(rendered)內容。4條內容邊界定義了盒的內容框(content box)
因此若是咱們給.box
類添加一個padding
爲10px的話,
.box { padding: 10px; }
浮動元素因爲是貼着包容塊在浮動,而此時的包容塊僅僅是.box
元素的內容區,不包含padding
,因此就出現了,浮動元素與.box
元素盒子之間的間距,效果以下:
OK,那如何經過只調整CSS的方式就達到咱們一開始腦海裏想象的渲染效果呢?答案就是讓.text
span元素成爲.float
元素的包含塊
就好了,讓inline level element
變成block level element
,只需添加一句dispaly:inline-block
或dispaly:block
便可,這裏咱們還想保持.text
元素的內聯性,因此咱們添加:
.text { display:inline-block; }
此時的效果就是咱們一開始想要的了
W3C的CSS標準規範中關於浮動的定義,一開頭就有這麼一句:
A float is a box that is shifted to the left or right on
the current line
.
翻譯成中文就是:
浮動(盒)就是一個在
當前行
向左或向右移動的盒。
你們注意高亮詞當前行(the current line)
,必定要理解這個當前行
,若是說包含塊(containing block)
決定了浮動元素浮動的範圍的話,那這個當前行(the current line)
就決定了在浮動範圍的哪一個垂直位置進行浮動。
一樣,咱們經過一個小場景來了解這個當前行
的重要性。
想象一下,你接到了一個任務,要求實現一個三列布局,不管左右兩列的寬度怎麼變化,中間列的寬度都要自適應,效果大概以下圖(爲了突出效果,給三列都添加了背景顏色):
聰明的你可能已經想到了辦法,讓左右兩列浮動,中間列的左右margin
值爲auto
,這樣就能夠實現中間列自適應了。沒錯你以爲十分機智,而後按照設計圖的視覺你從左到右寫了三個div
:
<style> .container { width: 600px; color:white; text-align:center; font-size:30px; } .left { float:left; background-color:yellow; width:200px; height:200px; } .right { float:right; background-color:red; width:200px; height:200px; } .middle { height: 200px; margin: 0 auto; background-color:blue; } </style> <div class='container'> <div class='left'>Left</div> <div class='middle'>Middle</div> <div class='right'>Right</div> </div>
然而你運行代碼,你看到的效果倒是這樣的:
而後你的心情奔潰了:
遇事不慌,首先讓咱們分析一下,浮動元素.right
的包含塊是什麼?沒錯,就是.container
的內容邊界(content edge)
,因此雖然有點差錯,但好歹還在裏面浮動着。
那接下來就是肯定當前行(current line)
了。
讓咱們還原到最開始的時候的佈局,去除.left
和.right
的浮動屬性,此時會有"三行"
首先咱們讓.left
浮動起來,在.container
的內容邊界範圍中、「第一行」中向左浮動,因爲其脫離了文檔流,.middle
開始上移到「第一行」。
此時因爲.middle
的上移,.right
元素也向上移動到了「第二行」,而後讓它浮動,此時.right
的浮動範圍是.container
的內容邊界範圍中,而浮動的當前行
是「第二行」,因此就出現了.right
元素掉下去浮動
的效果了,由於它的「當前行」就是「第二行」,它其實沒有掉下去過!
那怎麼樣才能解決,很簡單,讓.left
和.right
「同一行」不就行了。什麼意思呢?
.left
浮動的當前行是「第一行」,而後因爲脫離了文檔流,後續的元素會往上移動一行,那咱們讓.right
緊跟在.left
以後不就好了,.left
浮動後,.right
就會到「第一行」,此時浮動不就到了「第一行」的右邊了麼。而後因爲.right
也脫離文檔流,.middle
也上移到了「第一行」,具體代碼以下:
<div class='container'> <div class='left'>Left</div> <div class='right'>Right</div> <div class='middle'>Middle</div> </div>
而後就是運行以後就是咱們一開始想要的效果了:
看到這裏相信你已經理解了許多,讓咱們經過相關下面這段代碼的運行效果,來檢驗你是否真的理解了吧,提示:標題中的文字已經超出了.title
的寬度了
<style> .title { width:160px; } .more { float:right } </style> <h3 class='title'>我就是一個三級標題<a href='#' class='more'>更多</a></h3>
若是你能腦補出下圖的效果,說明你已經懂了,若是還不能,請回到前文繼續閱讀。
讓咱們用上面用過的套路來分析這一現象,首先確認.more
元素的包含塊爲.title
元素的內容邊界,而後因爲內容過長,寬度不夠,此時就變爲了兩行顯示,而.more
元素就在「第二行」,因此它的當前行就是「第二行」,添加浮動屬性以後,在.title
元素的內容邊界範圍內的「第二行」向右浮動,就造成了咱們看到的樣子。
若是但願不管標題內容不管多長,.more
元素都要固定浮動在右邊,那麼只須要將.more
元素的代碼放置帶.title
元素的最前方便可,也就是:
<h3 class='title'><a href='#' class='more'>更多</a>我就是一個三級標題</h3>
此時的效果就是咱們想要的了
這一部分實際上是浮動的本質,卻常常被咱們所遺忘,主要是由於這個文字環繞的效果主要影響的是浮動元素的跟隨元素。
因爲這一部分規範中的定義比較晦澀,因此如下內容是我在閱讀《CSS世界》結合自身的理解來闡述的,若是你但願查看規範的原文,能夠訪問這個連接。
首先因爲浮動,浮動元素和跟隨元素出現了必定的重疊區,這一點你們都知道了,而要想內容環繞,則重疊區不能有內容,注意是內容,文本、svg、圖片等替換元素都被視爲「內容」,基本都是inline或line-block的元素。
而不管是inline仍是inline-block元素,都會產生「行框盒子」,在重疊區中不容許出現「內容」,也就能夠轉化成重疊區的「行框盒子」須要「貼在」浮動元素浮動方向的反方向的側邊便可,就是說若是一個元素向左浮動,則跟隨元素在重疊區的「行框盒子」須要「貼在」浮動元素的右側邊,反之亦然。
讓咱們看一段代碼:
<style> .container{ width:250px; border:1px solid black; } .float { float:left; width: 100px; height:100px; border:2px solid red; } .paragraph { background-color:green; color:white; } .paragraph:first-line { background-color:blue; } </style> <div class='container'> <div class='float'></div> <div class='paragraph'> 我是匿名內聯盒子的文本 <span>,而我是內聯盒子的文本,若是文本很長,那就會出現balabalabala的效果。 </span> 充點字數哈兄弟。 </div> </div>
咱們用藍色背景高亮文本的第一行,就能夠看得出來「行框盒子」卡浮動元素側邊的效果了,而後注意,重疊區是不能渲染「內容」,背景顏色不屬於「內容」,因此咱們能夠看到綠色背景色連重疊區也鋪滿。
這時候可能有大兄弟要問,那重疊區究竟是浮動元素在上仍是跟隨元素在上啊?答案就是:浮動元素在上。
讓咱們加一段代碼驗證如下:
.float { background-color:yellow; }
效果以下:
當一個元素要進行浮動時,須要如下步驟: