一篇完整的FlexBox布局指南


一篇完整的FlexBox布局指南

轉載請標注本文鏈接並附帶以下信息: 譯:Cydiacen 作者:CHRIS COYIER 原文:A Complete Guide to Flexbox 原文更新於 2016-11-19

譯者的話

出於提升自身英語水平和鞏固FlexBox的知識,於是打算翻譯一篇比較知名的FlexBox布局的文章,當然這篇文章之前網上已有大漠的譯文,此次翻譯也有部分參考大漠譯文的內容,於是在此貼上大漠譯文的地址,以此致敬大佬。《一個完整的Flexbox指南

為了不浪費大家時間,先說明下flexBox現在的兼容情況:

  • (new)意味着已成為規范的新語法(比如:display:flex;
  • (tweener)意味着是來自2011年一種臨時的非官方的語法(display:flexbox;
  • (old)意味着來自2009年的老語法(display:box;
Chorme Safari Firefox Opera IE Android IOS
20- (old) 3.1+ (old) 2-21 (old) 12.1+ (new) 10 (tweener) 2.1+ (old) 3.2+ (old)
21+ (new) 6.1+ (new) 22+ (new) 11+ (new) 4.4+ (new) 7.1+ (new)

黑莓瀏覽器 10+ 支持新語法。

關於怎么樣混合語法可以得到更好的瀏覽器支持的信息,可以跳轉到《CSS-Tricks》或者《DevOpera》。

寫作背景

Flexbox(彈性盒子)布局模式(目前是個W3C規范草案)旨在為布局,對齊和分布容器內的子項提供一種更加高效的方式,即使這些玩意兒的大小是未知的或者動態變化的。(正如他的名字所示——Flex,彈性的意思)

Flex布局背后的主要思想是——給指定的容器提供修改其子項的寬、高乃至順序的能力,並且足夠完美的去填充可用的空間(主要是為了適應各種各樣的顯示設備和屏幕大小)。

一個使用了Flex布局的容器,將會擴展其子項以至於填充起可用的空間,或者縮小他們以防止溢出容器。

有一個相當重要的一點,FlexBox布局的方向不像常規布局(塊就是垂直從上到下,行就是水平從左到右),它是不可預知方向的。而那些常規的適合頁面布局,但對於作用在大型或者復雜的應用程序(特別是當他涉及到方向改變、大小變化、拉伸和收縮等)就缺乏靈活性。

注意: FlexBox布局最適用於應用程序的組件和小規模布局,而網格布局更適用於大規模的布局。

基本要素

因為FlexBox是一整個模塊並不是一個單獨的屬性,它涉及到很多東西包括它的所有設置屬性。一些屬性是需要被設置在容器(父級元素,稱為『彈性容器』),而一些其他的屬性需要被設置在子元素(稱為『彈性項』)中。

如果常規布局是基於塊布局與內聯布局的方向流的,那么彈性布局就是基於“flex-flow流”。請看一下來自W3C規范的這張圖,它解釋了彈性布局的主要思想。

基本上,彈性項(flex item)會沿着主軸方向(main-startmain-end)或側軸方向(cross-startcross-end)排列。

  • 主軸(main axis) - 彈性項主要是沿着彈性容器的主軸進行排列的。要注意一點,他不一定是水平的;這主要還是看flex-direction屬性(見下文)。
  • main-start | main-end - 彈性項將由main-startmain-end方向放置在容器內。
  • main size - 彈性項在主軸方向的寬度或高度就是主軸的尺寸。彈性項主要的大小屬性可以是寬度,也可以是高度屬性,由哪一個對着主軸方向決定。
  • cross axis - 與主軸垂直相交的軸線就是側軸。它的方向由主軸決定。
  • cross-start | cross-end - 彈性行是由彈性項填充起來的,它的配置是從容器的cross-start開始,往cross-end結束。
  • cross size - 彈性項在側軸方向的寬度或高度就是cross sizecross size根據側軸的方向來取決是寬度還是高度。

父級(彈性容器)屬性

display

這個屬性是定義在彈性容器上的;根據其值決定是內聯還是塊布局。這時它的直屬下級將會變成flex文檔流。

.container {
  display: flex; /* or inline-flex */
}

需要注意CSS的columns在flex容器里沒有效果。

flex-direction

這個是建立在主軸上的,從而定義了彈性項放置在容器的方向。FlexBox是單方向的布局概念。可以將彈性項視為主要布置在水平行或垂直列中。

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}
  • row(默認):在ltr排版方式下從左向右排列;在rtl排版方式下從右向左排列。
  • row-reverse:與row排列方向相反,在ltr排版方式下從右向左排列;在rtl排版方式下從左向右排列。
  • column:類似於row但是是頂部到底部
  • column-reverse:類似於row-reverse但是是底部到頂部

flex-wrap

彈性項默認會全部集中在一行。你可以使用這個屬性來改變這種情況,讓他們根據你的需要進行自動換行。文檔方向在這里也起作用,決定了新的一行被堆疊的方向。

.container{
  flex-wrap: nowrap | wrap | wrap-reverse;
}
  • nowrap(默認):單行顯示。在ltr排版下,項目自左向右;在rtl下,自右向左
  • wrap:多行顯示。在ltr排版下,項目自左向右;在rtl下,自右向左
  • wrap-reverse:多行顯示。與wrap相反

flex-flow(定義在彈性容器中)

這個是flex-directionflex-wrap屬性的縮寫版,它同時定義了彈性容器的主軸和側軸。默認是row nowrap

flex-flow: <‘flex-direction’> || <‘flex-wrap’>

justify-content

這屬性是用來定義主軸上的對齊方式的。當所有的彈性項在一行並且無法彈性伸展,或者可伸展但是達到了最大尺寸,它能幫助分配剩下的多余空間。並且當他們行內溢出時,這個屬性也可以對項目對齊施加一些控制。

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}
  • flex-start(默認):子項會從一行的起始處開始放置
  • flex-end:子項會從一行的結尾處開始放置
  • center:子項會集中在一行的中央
  • space-between:子項會被均勻的分布在行內;首項放置在一行的開始,尾項放置在一行的結束
  • space-around:子項會均勻的按照同等距離分布在一行。需要注意的是,在視覺上會覺得並不等距,因為所有子項在兩側都需要加上同等的空間。首項會與容器開始邊緣有一個單位空間的距離,但是與下一項會有兩個單位空間的距離,因為下一項也有它自己的適配空間。

align-items

這用來定義彈性項目在彈性容器的當前側軸上的默認行為。可以認為是側軸版的justity-content

.container {
  align-items: flex-start | flex-end | center | baseline | stretch;
}
  • flex-start:彈性項在側軸起點邊的外邊距緊靠住該行在側軸起始的邊。
  • flex-end:彈性項在側軸起點邊的外邊距緊靠改行在側軸結尾的邊。
  • center:彈性項會被放置在側軸的中央。
  • baseline:彈性項會根據他們的基線對齊。
  • stretch(默認):在側軸方向上拉伸彈性項以致填充滿彈性容器。(任遵從min-width/max-width

align-content

這個屬性會根據在側軸上的額外空間來排列容器的行,類似於justify-content在主軸在對齊單個彈性項的方式。

注意,這個屬性對於只有單行的彈性項來說是沒有效果的。

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
  • flex-start:行會緊靠容器的起始位
  • flex-end:行緊靠容器的結束位
  • center:行緊靠容器的中間位
  • space-between:每行會均勻分布;首行在容器起始處而最后行在容器結束處
  • space-around:每行根據相同的距離均勻的分布
  • stretch(默認):每行將會伸展以占用剩余的空間。

子項(彈性項)的屬性

order

一般來說,彈性項會按照文檔流的順序進行布局。然而,order屬性可以控制他們出現在彈性容器中的順序。

.item {
  order: <integer>;
}

flex-grow

這個屬性給予彈性項在需要的時候可以伸展的能力。它接收一個不帶單位的值作為比例。它規定了在容器內的彈性項可以占用多少的可用空間。

如果所有的子項都設置了flex-grow為1,那么容器內的剩余空間會被均勻的分配給所有自項。如果其中一項的值為2,那么這項的占用空間會是其他項的兩倍。

.item {
  flex-grow: <number>; /* default 0 */
}

設置負數是無效的。

flex-shrink

這定義了彈性項在需要的時候具有伸展的能力。

.item {
  flex-shrink: <number>; /* default 1 */
}

負數是無效的。

flex-basis

這定義了,當一個元素在被分配到剩余空間之前的默認大小。它可以是一個長度(如:20%,5rem等)或者一個關鍵字。auto關鍵字的意思就是『按照我的寬度和高度屬性調整尺寸』(他會暫時根據main-size來布局大小直到被棄用)。如果使用關鍵字content,意思就是『基於內容調整大小』——不過這個關鍵字並一定能很好的工作,因此很難去測試或者知曉它的兄弟們max-contentmin-contentfit-content做了什么。

.item {
  flex-basis: <length> | auto; /* default auto */
}

如果設置為0,額外空間內容不會被分解開來。如果設置成auto,額外空間會基於它的flex-grow的值進行分布。

flex

這是flex-growflex-shrinkflex-basis組合縮寫版。第二個和第三個參數(flex-shrinkflex-basis)是可選的。默認是0 1 auto

推薦你使用的這種縮寫屬性,這比設置單獨屬性更好。可以智能的通過縮寫形式設置值。

align-self

用來在單獨的伸縮項目上覆寫默認的對齊方式。

請看下align-items的解釋,幫助你了解可用值。

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

注意,floatclearvertical-align在彈性項中會失效。

例子

讓我們從一個非常非常簡單的例子開始,解決一個非常日常的問題:完美居中。如果你使用flexBox布局,這將會變得非常簡單。

.parent {
  display: flex;
  height: 300px; /* Or whatever */
}

.child {
  width: 100px;  /* Or whatever */
  height: 100px; /* Or whatever */
  margin: auto;  /* Magic! */
}

這個依賴於設置margin值為auto值,會自動獲取彈性容器的額外空間。因此設置垂直方向marginauto可以讓彈性項完美的居中在兩個軸。

現在讓我們使用下一些其他屬性。

考慮使用一個包含六個項的列表,並且為了視覺審美給他設置了一個固定大小尺寸,但他們也有可能可以自動獲取尺寸大小。我們想要他們可以均勻的,並且完美分布在水平軸上,並且當我改變瀏覽器的大小,他們還是可以很好的展示(不需要引用媒體查詢!)。

.flex-container {
  /* 我們先創建一個彈性布局環境*/
  display: flex;
  
  /* 然后如果我們允許子項換行可以定義flow-direction
   * 記住這相等於:
   * flex-direction: row;
   * flex-wrap: wrap;
   */
  flex-flow: row wrap;
  
  /* 然后我們再定義怎么樣分布剩余的空間 */
  justify-content: space-around;
}

完工。其他的一切不過是美化樣式。下面提供一些html,css代碼,可以在codePen調試並且改變下瀏覽器的大小看看會發生什么。
codePen

<ul class="flex-container">
  <li class="flex-item">1</li>
  <li class="flex-item">2</li>
  <li class="flex-item">3</li>
  <li class="flex-item">4</li>
  <li class="flex-item">5</li>
  <li class="flex-item">6</li>
</ul>

SASS:

@import "compass/css3";

.flex-container {
  padding: 0;
  margin: 0;
  list-style: none;
  
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  
  -webkit-flex-flow: row wrap;
  justify-content: space-around;
}

.flex-item {
  background: tomato;
  padding: 5px;
  width: 200px;
  height: 150px;
  margin-top: 10px;
  
  line-height: 150px;
  color: white;
  font-weight: bold;
  font-size: 3em;
  text-align: center;
}

讓我們再嘗試下其他東西。想象下,我們的網站所有頁面頭部都有個右對齊布局的導航,但是我們想讓他在中等大小的屏幕中居中顯示並且在小屏幕設備中單行顯示。非常簡單。

/* Large */
.navigation {
  display: flex;
  flex-flow: row wrap;
  /* This aligns items to the end line on main-axis */
  justify-content: flex-end;
}

/* Medium screens */
@media all and (max-width: 800px) {
  .navigation {
    /* When on medium sized screens, we center it by evenly distributing empty space around items */
    justify-content: space-around;
  }
}

/* Small screens */
@media all and (max-width: 500px) {
  .navigation {
    /* On small screens, we are no longer using row direction but column */
    flex-direction: column;
  }
}

codePen調試鏈接

讓我們再來試試一些更加靈活性的彈性項!關於移動先行,3列布局與頁眉頁腳全屏。和獨立的文檔順序。

.wrapper {
  display: flex;
  flex-flow: row wrap;
}

/* We tell all items to be 100% width */
.header, .main, .nav, .aside, .footer {
  flex: 1 100%;
}

/* We rely on source order for mobile-first approach
 * in this case:
 * 1. header
 * 2. nav
 * 3. main
 * 4. aside
 * 5. footer
 */

/* Medium screens */
@media all and (min-width: 600px) {
  /* We tell both sidebars to share a row */
  .aside { flex: 1 auto; }
}

/* Large screens */
@media all and (min-width: 800px) {
  /* We invert order of first sidebar and main
   * And tell the main element to take twice as much width as the other two sidebars 
   */
  .main { flex: 2 0px; }
  
  .aside-1 { order: 1; }
  .main    { order: 2; }
  .aside-2 { order: 3; }
  .footer  { order: 4; }
}

codePen

Flexbox前綴

Flexbox接受一些運營商前綴以支持可以在更多的瀏覽器上使用。它不僅只包括在屬性前添加前綴,它也有完全不同的屬性名字和值名字。這是因為Flexbox規范隨着時間一直在變化,因此有了oldtweenernew版本。

當然最好的方式是使用最新的語法,並且通過Autoprefixer運行你的css。

這有一段Sass @mixin可供選擇,他也可以給你提供一些需要怎樣處理的想法,幫助你處理一些前綴問題。

@mixin flexbox() {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
}

@mixin flex($values) {
  -webkit-box-flex: $values;
  -moz-box-flex:  $values;
  -webkit-flex:  $values;
  -ms-flex:  $values;
  flex:  $values;
}

@mixin order($val) {
  -webkit-box-ordinal-group: $val;  
  -moz-box-ordinal-group: $val;     
  -ms-flex-order: $val;     
  -webkit-order: $val;  
  order: $val;
}

.wrapper {
  @include flexbox();
}

.item {
  @include flex(1 200px);
  @include order(2);
}

相關屬性

Bugs

Flex當然不是沒有bug,我見過的關於這些bug收集最好的是Philip WaltonGreg WhitworthFlexBugs


免責聲明!

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



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