淺談彈性盒子布局


CSS3 彈性盒子(Flexible Box 或 Flexbox),是一種用於在頁面上布置元素的布局模式,使得當頁面布局必須適應不同的屏幕尺寸和不同的顯示設備時,元素可預測地運行。對於許多應用程序,彈性盒子模型提供了對塊模型的改進,因為它不使用浮動,flex容器的邊緣也不會與其內容的邊緣折疊。

許多設計師會發現彈性盒子模型更易於使用。彈性盒子中的子元素可以在各個方向上進行布局,並且能以彈性尺寸來適應顯示空間。由於元素的顯示順序可以與它們在源代碼中的順序無關,定位子元素將變得更容易,並且能夠用更簡單清晰的代碼來完成復雜的布局。這種無關性是僅限制於視覺呈現上的,語言順序以及基於源代碼順序的導航均不受影響。

注意: 雖然  CSS 彈性盒子布局規范 還處於最終征求意見稿 (Last Call Working Draft)階段(參見 最新編輯草案),並非所有瀏覽器都實現了彈性盒子的所有功能。但,這么說吧,現在全線產品對彈性盒子都有良好支持。最新的兼容性狀況可以查看每個具體屬性的 兼容性表格獲取。

彈性盒布局概念

在定義方面來說,彈性布局是指通過調整其內元素的寬高,從而在任何顯示設備上實現對可用顯示空間最佳填充的能力。彈性容器擴展其內元素來填充可用空間,或將其收縮來避免溢出。

塊級布局更側重於垂直方向、行內布局更側重於水平方向,與此相對的,彈性盒子布局算法是方向無關的。雖然塊級布局對於單獨一個頁面來說是行之有效的,但其仍缺乏足夠的定義來支持那些必須隨用戶代理(user agent)不同或設備方向從水平轉為垂直等各種變化而變換方向、調整大小、拉伸、收縮的應用程序組件。 彈性盒子布局主要適用於應用程序的組件及小規模的布局,而(新興的)柵格布局則針對大規模的布局。這二者都是 CSS 工作組為在不同用戶代理、不同書寫模式和其他靈活性要求下的網頁應用程序有更好的互操作性而做出的更廣泛的努力的一部分。

彈性盒布局相關詞匯

關於彈性盒子的討論已經從諸如水平/行內軸和垂直/塊級軸這些術語中解放出來,與此同時,需要有一套新的術語來正確描述此模型。在學習下面的詞匯項目時請對照下圖。圖中是一個 flex-direction 屬性為 row的彈性容器,意味着其內的彈性項目將根據既定書寫模式沿主軸水平排列,其方向為元素的文本流方向,在這個例子里,為從左到右。

彈性布局相關名詞

彈性容器(Flex container)
包含着彈性項目的父元素。通過設置  display 屬性的值為  flex 或  inline-flex 來定義彈性容器。
彈性項目(Flex item)

彈性容器的每個子元素都稱為彈性項目。彈性容器直接包含的文本將被包覆成匿名彈性單元。

軸(Axis)

每個彈性框布局包含兩個軸。彈性項目沿其依次排列的那根軸稱為主軸(main axis)。垂直於主軸的那根軸稱為側軸(cross axis)

  • flex-direction 確立主軸。
  • justify-content 定義了在當前行上,彈性項目沿主軸如何排布。
  • align-items 定義了在當前行上,彈性項目沿側軸默認如何排布。
  • align-self 定義了單個彈性項目在側軸上應當如何對齊,這個定義會覆蓋由 align-items 所確立的默認值。
方向(Direction)

彈性容器的主軸起點(main start)/主軸終點(main end)側軸起點(cross start)/側軸終點(cross end)描述了彈性項目排布的起點與終點。它們具體取決於彈性容器的主軸與側軸中,由 writing-mode 確立的方向(從左到右、從右到左,等等)。

  • order 屬性將元素與序號關聯起來,以此決定哪些元素先出現。
  • flex-flow 屬性是 flex-direction 和 flex-wrap 屬性的簡寫,決定彈性項目如何排布。
行(Line)

根據 flex-wrap 屬性,彈性項目可以排布在單個行或者多個行中。此屬性控制側軸的方向和新行排列的方向。

尺寸(Dimension)

根據彈性容器的主軸與側軸,彈性項目的寬和高中,對應主軸的稱為主軸尺寸(main size) ,對應側軸的稱為 側軸尺寸(cross size)

定義一個彈性盒子

為要使用此樣式的元素指派 CSS,需按以下方式設置 display 屬性:

display : flex

或者

display : inline-flex

這樣做將元素定義為彈性容器,其子元素則成為彈性項目。值 flex 使彈性容器成為塊級元素。值 inline-flex 使彈性容器成為單個不可分的行內級元素。

注意:廠商前綴標記會附加給 display 屬性值,而不是加給 display 屬性本身。例如: display : -webkit-flex

彈性項目須知

彈性容器直接包含的文本將自動包覆成匿名彈性項目。不過,一個只包含一系列空白符(如一堆空格或制表符等)的匿名彈性項目不會被渲染,就如同對其指派 display: none

對於彈性容器的絕對定位子元素來說,其靜態位置參照彈性容器的內容框的主起始角確定,而后依此完成此元素的定位。

相鄰的彈性元素其外邊距不會互相合並。使用 auto 外邊距可以吸收掉水平或垂直方向上的額外空間,這可以用於對齊或分隔相鄰的彈性項目。更多細節請參考 W3C 彈性框布局模型規范中的 Aligning with 'auto' margins

不像 CSS 中的其他對齊方法,彈性框的對齊屬性將進行“真正的”居中對齊。這意味着即使彈性條目溢出了彈性容器,它依然保持居中。不過這在某些時候可能會有問題。如果溢出超過了頁面的上邊緣或左邊緣(在從左到右的語言中,比如英語;在諸如阿拉伯語這樣從右到左的語言中這個問題更會出現在右邊緣),則雖然那些地方確實有內容,卻無法滾動到那些位置。在未來的發布版本里,對齊屬性將會有所擴展,使其包含有“安全”選項。目前,如果操心這點,可以改用外邊距來達成居中效果,因為外邊距會用比較“安全”的方式來響應變化,出現溢出時將停止居中。對這種需要居中的彈性項目,不使用 align- 屬性,而使用自動外邊距就能解決這個問題。對彈性容器中第一個和最后一個彈性項目的外側邊緣應用,也可以使用自動外邊距來替代 justify- 屬性。自動外邊距會自動伸縮來占滿剩余空間,當有剩余空間存在時彈性項目將會居中,如果沒有則切換至常規對齊方式。不過很不幸,如果嘗試在多行的彈性框中用基於外邊距的居中方法來替代 justify-content,就必須對每一行的第一個和最后一個彈性項目應用外邊距。此時除非能夠事先預測每一行都結束於哪個元素,否則就不能愉快的在主軸方向上用基於外邊距的居中方法來替代 justify-content 屬性了。

再強調一遍,元素的顯示順序與它們在源代碼中的順序無關,這種無關性只影響視覺呈現,語音順序以及基於源代碼順序的導航均不受影響。order 屬性並不影響語音和導航的次序。因此開發者們必須小心,合理地安排元素在源代碼中的順序,以免破壞文檔的可訪問性。

彈性盒子相關屬性

不影響彈性盒子的屬性

由於彈性盒子使用了不同的布局算法,某些屬性用在彈性容器上沒有意義:

  • 多欄布局模塊的 column-* 屬性對彈性項目無效。
  • float 與 clear 對彈性項目無效。使用 float 將使元素的 display 屬性計為block
  • vertical-align 對彈性項目的對齊無效。

示例

基本的彈性布局示例

這個基本的示例展示了如何對元素應用彈性布局,以及在彈性布局狀態下相鄰元素的行為方式。

<!DOCTYPE html> <html lang="en"> <head> <style> .flex { /* 基本樣式 */ width: 350px; height: 200px; border: 1px solid #555; font: 14px Arial; /* 建立彈性框 */ display: -webkit-flex; -webkit-flex-direction: row; display: flex; flex-direction: row; } .flex > div { -webkit-flex: 1 1 auto; flex: 1 1 auto; width: 30px; /* 讓過渡表現良好。(從/到"width:auto"的過渡 至少在 Gecko 和 Webkit 上是有 bug 的。 更多信息參見 http://bugzil.la/731886 ) */ -webkit-transition: width 0.7s ease-out; transition: width 0.7s ease-out; } /* colors */ .flex > div:nth-child(1){ background : #009246; } .flex > div:nth-child(2){ background : #F1F2F1; } .flex > div:nth-child(3){ background : #CE2B37; } .flex > div:hover { width: 200px; } </style> </head> <body> <p>Flexbox nuovo</p> <div class="flex"> <div>uno</div> <div>due</div> <div>tre</div> </div> </body> </html>

聖杯布局示例

此示例展示了彈性盒子根據不同屏幕分辨率動態改變布局的能力。下圖說明了這種轉換。

HolyGrailLayout.png

這里展示的正是針對瀏覽器窗口的頁面布局必須為智能手機窗口優化的場景。不僅元素的尺寸需要縮減,其呈現順序也需要改變。彈性盒子讓這變得很簡單。

<!DOCTYPE html> <html lang="en"> <head> <style> body { font: 24px Helvetica; background: #999999; } #main { min-height: 800px; margin: 0px; padding: 0px; display: -webkit-flex; display: flex; -webkit-flex-flow: row; flex-flow: row; } #main > article { margin: 4px; padding: 5px; border: 1px solid #cccc33; border-radius: 7pt; background: #dddd88; -webkit-flex: 3 1 60%; flex: 3 1 60%; -webkit-order: 2; order: 2; } #main > nav { margin: 4px; padding: 5px; border: 1px solid #8888bb; border-radius: 7pt; background: #ccccff; -webkit-flex: 1 6 20%; flex: 1 6 20%; -webkit-order: 1; order: 1; } #main > aside { margin: 4px; padding: 5px; border: 1px solid #8888bb; border-radius: 7pt; background: #ccccff; -webkit-flex: 1 6 20%; flex: 1 6 20%; -webkit-order: 3; order: 3; } header, footer { display: block; margin: 4px; padding: 5px; min-height: 100px; border: 1px solid #eebb55; border-radius: 7pt; background: #ffeebb; } /* 窄到已不足以支持三欄 */ @media all and (max-width: 640px) { #main, #page { -webkit-flex-flow: column; flex-direction: column; } #main > article, #main > nav, #main > aside { /* 恢復到文檔內的自然順序 */ -webkit-order: 0; order: 0; } #main > nav, #main > aside, header, footer { min-height: 50px; max-height: 50px; } } </style> </head> <body> <header>header</header> <div id='main'> <article>article</article> <nav>nav</nav> <aside>aside</aside> </div> <footer>footer</footer> </body> </html>

試驗場地

有幾個在線彈性盒子試驗場地可供進行各種實驗:

務必牢記

描述彈性項目如何排布的算法有時會極其棘手。在使用彈性盒子進行設計時,請考慮以下幾點,以免碰到不好的意料外狀況。

彈性盒子的排布與書寫模式是一致的,這意味着排布的主軸起點主軸終點根據的是開始結束的位置。

側軸起點側軸終點依賴於開始前面(before)的位置定義,而這個“前面”依賴於 direction 的值。

只要 break- 屬性的設置值允許,在彈性框布局中是可以存在分頁的。CSS3 中的 break-afterbreak-before 和 break-inside,以及 CSS 2.1 中的 page-break-beforepage-break-after 和 page-break-inside 屬性在彈性容器上、彈性項目上和彈性項目內均可以使用。

瀏覽器兼容性

 

特性 Firefox (Gecko) Chrome Internet Explorer Opera Safari
基礎支持(單行彈性框) 18.0 (18.0)[6]-moz[2]
22.0 (22.0)
21.0-webkit
29.0
11[3] 12.10-webkit[5] 6.1-webkit[1]
多行彈性框 28.0 (28.0) 21.0-webkit
29.0
11[3] 12.10[5]
15 -webkit
6.1-webkit[1]

 

[1] Safari 在版本 6.0 (iOS.1)以前支持的是規范的一個與現有版本不兼容的舊版草案。Safari 6.1(以及 iOS 7 上的 Safari)已更新為支持最終版本。

[2] 直到 Firefox 22 位置,用戶必須修改 about:config 設置,將 layout.css.flexbox.enabled 改為true 才能激活對彈性盒子的支持。從 Firefox 22 到 Firefox 27,此設置項默認為 true,而 Firefox 28 中取消了此設置項。

[3] Internet Explorer 10 支持的是規范的一個與現有版本不兼容的舊版草案;Internet Explorer 11  已更新為 支持最終版本。

[4] Android 瀏覽器直到 4.3 為止支持的是規范的一個與現有版本不兼容的舊版草案。Android 4.4 已更新為支持最終版本。

[5] 在 Opera 12.10 的彈性盒子初始實現中是沒有前綴的,但 Opera 版本 15 到 16 和 Opera Mobile 的 15 到 19 需要 -webkit. 在 Opera 17 及 Opera Mobile 24 中再次取消了前綴。

[6] 直到 Firefox 29 為止,在彈性項目上指定 visibility: collapse 將使其被視為 display: none 處理,而預期的行為是被視為 visibility: hidden。建議的處理方式是在彈性項目上使用visibility:hidden,這樣其行為應當與指派了 visibility:collapse 一致。更多信息,參考 bug 783470.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM