轉載自張鑫旭-鑫空間-鑫生活[首頁 ? 張鑫旭]

本文地址:CSS box-flex屬性,然後彈性盒子模型簡介 ? 張鑫旭

一、淡淡的開頭語

昨天趁著不想工作的時間間隙閑逛24ways,在My CSS Wish List一文中,見到了個新鮮的CSS屬性,就是題目中的box-flex,以前沒有見過,頓生疑惑,不知是騾子還是馬,於是習慣性谷歌之,真是不穀不知道,一谷嚇一跳。倒不是該屬性本身,而是此屬性作為導火索,讓我瞭解了下CSS3中新的盒子模型——彈性盒子模型(Flexible Box Model)。對於我這樣的流體佈局控而言,這種盒子模型的出現就好比打麻將槓上開花槓到絕張邊七條,讓人興奮不已。在國外,彈性盒子模型早在去年就開始被提及,研究,與應用。然而,自己現在才第一次聽到此概念,真是一不留神就out了,學習這東西,果然鬆懈不得。

本文內容敘述撇開以往順流而下的方式,直接以box-flex屬性為切入口,直入大本營,再鋪開敘述。

添加於2014-11-30:本文已老,僅供參考。

二、box-flex屬性(和諧版)

有道桌面詞典顯示,」flex」一詞中文有「收縮」之意。不過,從此屬性實際上產生的效果來看,無論怎樣用「收縮」一詞解釋都顯得很牽強。所以,這裡,直接拋開字面意思,我們可以將」box-flex」理解為」房子-分配」。box為「盒子」的意思,我們可以理解為當下價格巨高的「房子」,」flex」指兄弟幾個「分配房子」。

舉個更實際點的例子:馬林大叔省喫儉用一輩子,終於在上海郊外買了間150平米的商品房。後來,馬林大叔想回老家養老,決定把房子分配給他的三個兒子。ok,先暫停下,這裡提到的「房子」就是」box-flex」中的」box」,「分配」就是」box-flex」中的」flex」,於是,這個「分配房子」的舉動就稱為」box-flex」,而box-flex屬性的值就是說的如何分配,分配比例是什麼。oK,繼續我們的例子,馬林大叔的三個兒子分別叫做大馬,中馬和小馬,其中大馬已經結婚多年,有一堆雙胞胎女兒,拖家帶口的人多;而中馬和小馬是優秀的光棍人士。所以,大馬要求分配更多的房子,最終,家人一番協商有了下面的分配結果,就是:

#大馬 { 房子-分配: 2; }
#中馬 { 房子-分配: 1; }
#小馬 { 房子-分配: 1; }

我想,上面的分配應該很容易看懂的。房子分成了總共4份,其中有家室的大馬分得其中的兩份,而為國家省橡膠的中馬和小馬每人分得其中一份,於是用數值換算就是:

大馬 = 150 * (2 / (2+1+1)) = 75(平米);中馬 = 150 * (1 / (2+1+1)) = 37.5(平米);小馬 = 150 * (1 / (2+1+1)) = 37.5(平米);

如果裝換成CSS表示就是:

#first_boy { box-flex: 2; }
#second_boy { box-flex: 1; }
#three_boy { box-flex: 1; }

哇咔咔,box-flex的含義與作用理解瞬間柳暗花明:用來按比例分配父標籤的寬度(或高度)空間。

box-flex的值為至少為1的整數時起作用。但是,僅僅一個box-flex屬性是不足以實現子元素間的空間分配,因為還要看其老爸的意思。所謂,我爸是李剛,撞人很囂張;恨爸不是剛,撞人心慌慌。只有老爸開口說:「這個房子現在你們隨意分配。」其子女才能分配。

所以,父元素也是需要添加必要的聲明的。此聲明就是:

#father { display: box; }

似乎也可以是:

#father { display: inline-box; }

此聲明好像是在說:孩子們,現在我把這個房子變成了可隨意分配狀態,非固定財產,你們可以自己協商分配了。

display: box;的聲明其實就是彈性盒子模型的聲明,此聲明下的子元素的行為與表現與CSS2中的傳統盒子模型的表現是有顯著的差異的。

畢竟屬於CSS3的東西,目前而言,僅Firefox/Chrome/Safari瀏覽器支持彈性盒子模型(IE9不詳,Opera尚未),且使用的時候,需要附帶私有前綴。就是諸如-moz-, -webkit-之類。

CSS實例

現在把上面的馬林分房子的例子CSS實例化,看看在web頁面上是個如何的表現://zxx:有把小說拍成電影的感覺,

主要CSS代碼如下:

.test_box {
display: -moz-box;
display: -webkit-box;
display: box;

...
}
.list {
...
}
.list_one {
-moz-box-flex: 1;
-webkit-box-flex: 1;
box-flex: 1;
}
.list_two{
-moz-box-flex: 2;
-webkit-box-flex: 2;
box-flex: 2;
}

HTML代碼如下:

<div class="test_box">
<div class="list list_two">1</div>
<div class="list list_one">2</div>
<div class="list list_one">3</div>
</div>

結果如下縮略圖:

從上圖可以看去,老大大馬確實分配到了2份的房子空間,而中馬和小馬均分到了一份房子空間。

您可以狠狠地點擊這裡:box-flex彈性佈局測試demo

三、CSS box-flex屬性(不和諧版)

繼續上面馬林大叔分房的例子。原本兄弟三人和和睦睦是一點問題都沒有的,房子怎麼分也基本都定下來了。然而,突然,事情起了波瀾。老三小馬突然有了個彪悍的女朋友,叫阿鳳。小馬本人對分配房子的大小是覺得無所謂的,即使兩個人住,近40平米的屋子也足夠了,何必為了這點事情傷了兄弟們間的和氣。然而,小馬的女友阿鳳卻是個喫不了虧的人,說什麼也要爭口氣,於是,找來大馬中馬,強烈要求要加大他們房子的分配面積。

在大馬,中馬看來,阿鳳還屬於外來人,憑什麼對他們兄弟的房子指手劃腳,於是,沒得妥協,於是,爭執不斷,於是,愈演愈烈,於是,不可開交。於是,有天,阿鳳實在憋不住了,在廚房做菜的時候突然拿著菜刀跑出來,大聲咆哮:「不管怎樣,反正我家小馬至少要50平米的房子,其餘的怎麼分是你們的事情,我不管,這是我的底線了,再低就沒得商量!!」大馬等被這架勢嚇住了,最終還是妥協了:小馬就50平米(即使以後房子擴建還是50平米),剩下的面積大馬,中馬2:1比例再分配。於是就有:

#大馬 { 房子-分配: 2; }
#中馬 { 房子-分配: 1; }
#小馬 { 房子-分配: 50m2; }

改編成CSS劇本就是:

#first_boy { box-flex: 2; }
#second_boy { box-flex: 1; }
#three_boy { width: 50px; }

還是不難理解,當子元素中有寬度值的時候,此元素就定寬處理,剩下的空間再按比例分配。

於是,此時,大馬的房子大小是:(150 – 50) * (2 / (1 + 2)) = 66.7平米,中馬分配房子大小是:(150 – 50) * (1 / (1 + 2)) = 33.3平米。

還是類似上面的demo,看看含有定寬元素的子元素是如何表現的。

新增CSS樣式如下:

.list_w300 { width: 300px; }

HTML代碼如下:

<div class="test_box">
<div class="list list_two">1</div>
<div class="list list_one">2</div>
<div class="list list_w300">3</div>
</div>

結果如下縮略圖:

老三分得300像素的寬度,剩下的500像素寬度老大和老二2:1比例分配。

您可以狠狠地點擊這裡:含定寬元素彈性佈局demo

然而,事情還沒有結束。兄弟幾個相處了一段時間後發現,偌大的屋子如果全部都是私有的話,會有諸多生活上的不便。所以,需要騰出些公共空間,給屋子透個氣。咋辦呢,老三小馬的女友阿鳳死活不妥協,沒有辦法,老馬和中馬只能犧牲自己的住所面積作為公共空間了。

反應到CSS上,大致就是增加了margin間距,如下HTML:

<div class="test_box">
<div class="list list_two">1</div>
<div class="list list_one" stylex="margin:0 30px;">2</div>
<div class="list list_w300">3</div>
</div>

結果如下縮略圖:

老大,老二的空間同時被壓榨了,老大還好,原本比例高。只是可憐了二當家的,地方越來越小。不過,老二的隱忍換來了和睦,所做的犧牲沒有白費。

四、爸爸其實很厲害,的說~

語言小知識:「厲害」用日語說的話,動漫裡面經常用的比較文雅的就是「すごい」,現在年輕人常用的就是「スゲ」,還有一種說法「よくできるね」是一種稱讚的說法,語氣比較柔和。

彈性盒子模型下的爸爸(父標籤)其實是很有貨的,男人嘛,就應該這樣,夠沉穩夠內涵。

爸爸肚子中的貨有:box-orient, box-direction, box-align, box-pack, box-lines. 現在依次講講這裡box打頭的屬性都是幹嘛用的。

box-orient

box-orient用來確定子元素的方向。是橫著排還是豎著走。可選的值有:

horizontal | vertical | inline-axis | block-axis | inherit

其中,inline-axis是默認值。且horizontal與inline-axis的表現似乎一致的,讓子元素橫排;而vertical與block-axis的表現也是一致的,讓元素縱列。

我專門做了個demo頁面,方便您查看各個值的行為與表現。您可以狠狠地點擊這裡:box-orient值作用測試頁面

切換demo頁面左邊的單選選項卡(如果您的瀏覽器為Firefox/Chrome/Safari),就可以看到不同的box-orient屬性值的行為表現了。//zxx:對比可以發現,Firefox下的display:box會收縮外框(有點display:inline-block的感覺),而Chrome則沒有收縮。

box-direction

box-direction是用來確定子元素的排列順序,可選值有:

normal | reverse | inherit

其中normal是默認值,表示按照正常順序排列。所謂正常順序,就是我們看書寫文字的順序,從左往右,由上至下,先出現的元素,就上面或是左邊。而reverse表示反轉,原本從左往右應該是1-2-3的,結果顯示確實3-2-1。

例如我們將此屬性應用在我們一開始的分配房子的demo上的話,最後的顯示就會如下縮略圖——順序反過來的:

相關CSS代碼如下:

.test_box {
display: -moz-box;
display: -webkit-box;
display: box;

-moz-box-direction:reverse;
-webkit-box-direction:reverse;
box-direction:reverse;

...
}

您可以狠狠地點擊這裡:列表順序反轉顯示demo

box-align

box-align與box-pack都是決定盒子內部剩餘空間怎麼使用的。在行為效果上就是表現為「對齊」,這跟Adobe的軟體中的一些「對齊」是一致的,例如化妝大師photoshop中的圖層-對齊:

其中box-align決定了垂直方向上的空間利用,也就是垂直方向上的對齊表現。為了便於記憶,我們可以拿來和CSS2中的vertical-align隱射記憶,兩者都有」align」,都是都是垂直方向的對齊;而剩下的box-pack就是水平方向的了。

box的可選參數有:

start | end | center | baseline | stretch

其中stretch為默認值,為拉伸,也就是父標籤高度過高,其孩子元素的高度就多高,//zxx:以後等高佈局不用愁了。start表示頂邊對齊,end為底部對齊,center為居中對齊,baseline表示基線(英文字母o,m,n等的底邊位置線)對齊。

為了直觀的知道各個值的效果,我做了個可實時查看效果的demo,您可以狠狠地點擊這裡:css box-align各值效果demo

點擊demo左邊的單選按鈕組,即可查看各個屬性值的效果。

例如,選中」center」這個單選按鈕,結果右側的顯示如下面的截圖:

其他各個屬性值的效果您可以自己點擊查看(非IE瀏覽器),這裡就不一一展示效果截圖了。

box-pack

box-pack決定了父標籤水平遺留空間的使用,其可選值有:

start | end | center | justify

就大部分的行為表現來說分別對應text-align屬性的值:left | right | center | justify;但是,之所以box-pack不使用」left」, 而是」start」,是因為box-direction屬性,這玩意可以反轉原本的排列,原本的「左對齊」反轉後結果是「右對齊」了,此時」left」顯然就詞不達意了,所以使用」start」更具有概括性,就是與父標籤的起始位置對齊,從而不會產生語義與行為上的困擾。

其中」start」是box-pack屬性的默認值,justify表示兩端對齊。

為了方便直觀的查看各個屬性值的效果,我製作了與上面類似風格的demo,您可以狠狠地點擊這裡:box-pack屬性值效果demo

下為選中end的界面截圖縮略圖:

貌似發現在Firefox瀏覽器下,justify是沒有反應的,可能還未支持。Chrome瀏覽器表現良好。

box-lines

box-lines是用來決定子元素是可以換行顯示呢?還是就算擠出油還是單行顯示。兩個可選值:

single | multiple

其中single是默認值,表示死活不換行,如下圖所示:

設置box-lines:multiple後,就多行顯示了。不過我自己測試了下,貌似現在無論是Firefox瀏覽器還是Chrome都不認識box-lines:multiple屬性,是暫不支持呢,還是什麼什麼?

您可以狠狠地點擊這裡:看不到換行效果的demo

五、兩個遺漏的屬性

子元素除了box-flex屬性,還有兩個屬性,box-flex-group和box-ordinal-group,其中box-flex-group的作用不詳,貌似目前瀏覽器也不支持;box-ordinal-group的作用是拉幫結派。還是上面馬林大叔分房子的例子。小馬女友阿鳳又不消停,眼瞅著大馬的房子面積比自己大好多,心裡不平衡,於是,就去拉攏中馬,一起打大馬房子的主意。這個「拉攏」就是這裡的box-ordinal-group,拉攏的組織團夥是有一個數字級別的,決定了你這個組織的位置。

數值越小,位置就越靠前,這不難理解,第一組在最前嘛,隨後第二組,第三組… 例如:box-ordinal-group:1的組就會在box-ordinal-group:2的組前面顯示。於是,我們可以利用這個屬性改變子元素的順序。例如下面這個例子:

HTML代碼如下:

<div class="test_box">
<div class="list list_two">1</div>
<div class="list list_one">2</div>
<div class="list list_one">3</div>
</div>

相關CSS如下:

.list_one {
...

-moz-box-ordinal-group: 1;
-webkit-box-ordinal-group: 1;
box-ordinal-group: 1;
}
.list_two{
...

-moz-box-ordinal-group: 2;
-webkit-box-ordinal-group: 2;
box-ordinal-group: 2;
}

結果後面兩個class為」list_one」的元素跑到前面去了。如下圖所示:

您可以狠狠地點擊這裡:box-ordinal-group分組改序demo

六、實際點的應用

如果您現在瀏覽器地址欄中的地址中含有」首頁 ? 張鑫旭」字樣,並且瀏覽器為較新的Firefox/Chrome/Safari瀏覽器,那麼您就可以在本頁面上找到我做的應用。

咔咔,我就不賣賣關子了,我改變了相關文章某一處的顯示順序,就是隨機文章。

但是在本文所在的頁面上,隨機文章第一個顯示了(由於贊不支持換行,故垂直顯示了)。

相關CSS代碼如下:

.similarity ul{display:-moz-box; display:-webkit-box; display:box; -moz-box-orient:vertical; -webkit-box-orient:vertical; -o-box-orient:vertical; box-orient:vertical; }
.similarity ul li{-moz-box-flex:1; -webkit-box-flex:1; box-flex:1; -moz-box-ordinal-group:2; -webkit-box-ordinal-group:2; box-ordinal-group:2;}
.similarity ul li:last-child{-moz-box-ordinal-group:1; -webkit-box-ordinal-group:1; box-ordinal-group:1; }

七、參考文章

  • My CSS Wish List
  • The CSS 3 Flexible Box Model
  • Introducing the Flexible Box Layout module
  • -moz-box-flex
  • Flexible Box Layout Module W3C Working Draft, 23 July 2009

推薦閱讀:

相關文章