引子:給你們出一個小小的考題,如何使用css來實現相似下面的在指定區域內,內容自適應的垂直居中。css
在好久好久之前,有一個並不堅挺的方式來實現。html
display:table-cell屬性指讓標籤元素以表格單元格的形式呈現,相似於td標籤。web
其實,心裏裏討厭這個方式的緣由有不少,chrome
好比,高級瀏覽器都是支持此屬性的,可是低級瀏覽器就只能對你說sorry了。對於須要使用各類並不精準的其餘屬性,如font-size來「輔助 治療」,在不一樣場合容易出現一些預期以外的bug。若是一個問題經過新特性和老特性均可以解決,我想全部人都會選擇通用,而且穩定性好的那一種。瀏覽器
好比,經歷過table年代的攻城師們想起table沾邊的就讓人以爲一點也不高大上,深深的產生厭惡感。app
那麼,該如何實現更合理呢?………..請耐心讀完這篇長篇大論的博客。less
接下來進入正題。ide
說一個定義,他是一種抽象的玩意,他叫作IFC : inline formating context(行內格式化上下文)佈局
與IFC之對應的是BFC : block formating context(塊級格式化上下文),BFC在網頁佈局中的應用場景更是極其豐富,瞭解它會了解不少bug出現的緣由,以及自行找到解決辦法。可是此篇博 客不是討論他的,因此即便說到了他有了一肚子的傾訴欲也得留到下次再說。網站
IFC跟BFC同樣,它不是一個元素,不是一種屬性,而是一種環境,一種上下文,一種佈局特性。
引用w3c(http://www.w3.org/TR/CSS2/visuren.html#inline-formatting)
In an inline formatting context, boxes are laid out horizontally, one after the other, beginning at the top of a containing block. Horizontal margins, borders, and padding are respected between these boxes. The boxes may be aligned vertically in different ways: their bottoms or tops may be aligned, or the baselines of text within them may be aligned. The rectangular area that contains the boxes that form a line is called a line box.
The width of a line box is determined by a containing block and the presence of floats. The height of a line box is determined by the rules given in the section on line height calculations.
A line box is always tall enough for all of the boxes it contains. However, it may be taller than the tallest box it contains (if, for example, boxes are aligned so that baselines line up). When the height of a box B is less than the height of the line box containing it, the vertical alignment of B within the line box is determined by the ‘vertical-align’ property. When several inline-level boxes cannot fit horizontally within a single line box, they are distributed among two or more vertically-stacked line boxes. Thus, a paragraph is a vertical stack of line boxes. Line boxes are stacked with no vertical separation (except as specified elsewhere) and they never overlap.
In general, the left edge of a line box touches the left edge of its containing block and the right edge touches the right edge of its containing block. However, floating boxes may come between the containing block edge and the line box edge. Thus, although line boxes in the same inline formatting context generally have the same width (that of the containing block), they may vary in width if available horizontal space is reduced due to floats. Line boxes in the same inline formatting context generally vary in height (e.g., one line might contain a tall image while the others contain only text).
When the total width of the inline-level boxes on a line is less than the width of the line box containing them, their horizontal distribution within the line box is determined by the ‘text-align’ property. If that property has the value ‘justify’, the user agent may stretch spaces and words in inline boxes (but not inline-table and inline-block boxes) as well.
When an inline box exceeds the width of a line box, it is split into several boxes and these boxes are distributed across several line boxes. If an inline box cannot be split (e.g., if the inline box contains a single character, or language specific word breaking rules disallow a break within the inline box, or if the inline box is affected by a white-space value of nowrap or pre), then the inline box overflows the line box.
When an inline box is split, margins, borders, and padding have no visual effect where the split occurs (or at any split, when there are several).
Inline boxes may also be split into several boxes within the same line box due to bidirectional text processing.
Line boxes are created as needed to hold inline-level content within an inline formatting context. Line boxes that contain no text, no preserved white space, no inline elements with non-zero margins, padding, or borders, and no other in-flow content (such as images, inline blocks or inline tables), and do not end with a preserved newline must be treated as zero-height line boxes for the purposes of determining the positions of any elements inside of them, and must be treated as not existing for any other purpose.
一大堆英文看的鴨梨山大,通過我的的理解總結,翻譯和理解以下(原諒個人東北話和長篇大論):
在IFC中,內聯元素在水平方向上一個接一個的排布,其中,容器之間水平方向上的margin,padding,border方向上是好使的。他們垂直方向上有不少種對其方式,好比居底部或頂端對齊,或者基線對齊。他們對齊完了以後造成的這個四方塊兒區域,叫作一個line box(行框)。
一個line box的寬度由包含它的元素的寬度和包含它的元素裏面有沒有float元素來決定,而高度由內部元素中實際高度最高的元素而計算出來。
//其實這句話解釋了爲何內聯元素是不能設置垂直方向的padding,margin等,由於即便設置了,也不會影響line box的高度,可能會在每一個瀏覽器的表現各異,但大多數不會達到預期的效果。
line box的高度是足夠高來包含他內部的容器們的,也可能比它包含的容器們都高(好比在基線對齊的時候),當他包含的內部容器的高度小於line box的高度的時候,內部容器的垂直位置由本身的vertical這個屬性來肯定。當內部的容器盒子太多了一個line box裝不下來,他們折行以後會變成兩個或者多個line box, line box們相互之間垂直方向不能分離,不能重疊。
通常來講,line box的左邊緣挨着包含它的元素的左邊緣,而且右邊緣挨着包含它的元素的右邊緣,浮動元素會在包含他們的元素的 邊緣和line box的邊緣之間,因此,雖然在同一個IFC下的line box們一般擁有相同的寬度(就是包含他們的容器的寬度),可是也會由於浮動元素的搗亂,致使line box們的可用寬度產生了變化不同了。在同一個Ifc下的line box們的高度也會不同(好比說,一個line box裏有個比較大的image,他就高了)。
我的補充:
line box 圖(趁機秀照片):
若是一個line box 裏的內聯元素們的寬度總和小於這個line box的寬度,那麼他們在這個line box裏的水平方向的排布方式由 text-align這個屬性來決定,若是這個屬性被設置成了「justify」,可使這些盒子在剩餘空間內拉伸(除了inline-table 和 inline-block的元素)。//實現相似兩端對齊的效果,但不是全部瀏覽器都支持。
當內聯元素的寬度超過了line box的寬度,那麼它會折行分裂成了幾個line box,若是這個元素裏面的內容不能夠折行,例如只有一個字,或者white-space設置了nowrap/pre。那麼內聯元素會溢出line box。
當一個內聯元素分裂時,分裂處的 margins, borders 和 padding不會有任何視覺效果(或者其餘任何分裂,只要是有多個line box)。
line box 的生存條件是在IFC中而且包含inline-level元素,若是line box裏沒有文本,空白,換行符,內聯元素,也沒有其餘的存在IFC環境中的元素,(如inline-block,inline- table,images等),將會被視爲零高度,也將會被視爲沒有意義。
補充:在IFC的環境中,是不能存在block-level元素的,若是將block-level元素插入到IFC中,那麼此IFC將會被破壞掉, 而block-level元素前的元素和block-level元素後的元素將會各自自動產生一個匿名容器其包圍,這個匿名的容器內部環境將是一個新的 IFC。
例1:
P是一個塊元素,它包含了5個內聯元素,其中,有三個是匿名的。
這段代碼裏,在line box裏,有5個inline的元素,P創建了包含line box的容器箱。
若是這個P的寬度足夠,將會產生惟一的一個line box。以下圖:
若是P的寬度不夠,將會被分割成多個line box。以下圖:
例2:
1.margin,在emphasized前和word以後水平方向上起了做用。分割處無做用,垂直方向無做用。
2.padding,在emphasized前和word以後水平方向上起了做用。分割處無做用,垂直方向無做用。
3.border,看那個虛線的表現形式。
通過了上面的闡述,咱們回到博客開使的問題上。實現未知尺寸的文本/元素/圖片 在某個元素內垂直居中。
上面曾經說過:
在一個line box中,當他包含的內部容器的高度小於line box的高度的時候,內部容器的垂直位置由本身的vertical這個屬性來肯定。
那麼,咱們設想一下,若是手動建立一個IFC的環境,讓line box的高度是包含塊的高度的100%,讓line box內部的元素使用vertical-align:middle,就能夠實現垂直居中。
一個line box的高度由內部元素中實際高度最高的元素而計算出來。
因此,咱們在line box中插入一個高度100%的inline-block元素。則會把整個line box撐高直到包含塊的100%.
概念圖:
其中,高級瀏覽器能夠直接在外面的包含層使用:after來在內部追加建立一個僞元素,而低級瀏覽器不支持:after的寫法,則在html模板中 建立一個空的元素, 設置其高度爲100%則與包含層相同,寬度爲零,內容爲空,則能夠實現將本身內部撐大爲一個line box,但不佔據任何空間。那麼本身內部的其餘元素能夠經過轉化爲inline 或者 inline-block 來實如今line box中的垂直居中。表現形式就是在外面的包含層中垂直居中。
代碼以下:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>IFC應用實例</title> <meta name="copyright" content="www.ohweb.cn" /> <meta name="author" content="weinan" /> </head> <body> <style> /* comm 核心部分 */ .g-ifc-wrap:after, .g-ifc-wrap-after{content:'';height:100%;width:0;display:inline-block;*display:inline;*zoom:1;margin-left:-5px;font-size:0;vertical-align:middle;} .g-ifc-item{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;} /* test */ #test{height:300px;width:500px;background-color:#878787;border:3px solid #526f39;} #test p{background-color:#7ff30a;color:#000;font-weight:bold;} </style> <div id="test" class="g-ifc-wrap"> <p class="g-ifc-item">我想要基於外面的容器居中</p> <img class="g-ifc-item" alt="我也是" src="http://dh2.kimg.cn/v/upload/20140325/9aa6e7f4e477d9af9c463c5604070ed4.jpg?v=1395739057" /> <!--[if lte IE 7]><span class="g-ifc-wrap-after"></span>< ![endif]--> </div> </body> </html>
表現形式以下:
chrome等高級瀏覽器:
IE6:
小結 :
當咱們詳細的瞭解IFC的原理以後,能夠更有自信的應用它來作不少事情。
例若有些網站會摒棄float這種bug多多的佈局方式,而所有使用IFC的環境來進行佈局(固然了,很精確的時候也須要解決inline-level元素之間的間隙)。
或者實現一些如圖片文字的居中對齊,自適應高度等不少靈活的效果。
同時,當咱們的網頁產生一些bug的時候,咱們也能夠明白爲什麼如此而且思考好的解決方法而不是去網上找「萬金油」。這將使咱們對本身的網頁有了更深的掌控性。
————————————–END