理解Flexbox:你需要知道的一切

w3cplus發表於2017-03-28

  這篇文章介紹了Flexbox模組所有基本概念,而且是介紹Flexbox模組的很好的一篇文章,所以這篇文章非常的長,你要有所準備。

 學習Flexbox的曲線

  @Philip Roberts在Twitter上發了一個推:

  學習Flexbox可不是件很有趣的事情,因為它將挑戰你所知道的CSS佈局方面的知識。當然這也是非常正常的,因為一切知識都是值得學習的。

  另外你要認值對待Flexbox。因為它是現代Web佈局的主流方式之一,不會很快就消失。它也成為一個新的W3C標準規範。既然如此,那讓我們張開雙臂,開始擁抱它吧!

 你將學習

  我將帶你先了解Flexbox的一些基礎知識。我想這是開始嘗試學習Flexbox的必經階段。

  學習基礎知識是件很有意思的事情,更有意思的是可以通過學習這些基礎理論知識,在實際的應用程式中使用Flexbox。

  我將帶您親歷很多“小知識點”之後,在文章末尾,使用Flexbox來做一個音樂應用程式的佈局(UI介面佈局)。

  看上去是不是棒棒的?

  在開始進入學習Flexbox構建音樂應用程式的佈局之前,你還將需要了解Flexbox在響應式Web設計中所起的作用。

  我將會把這一切都告訴你。

  上圖是@Jona Dinges設計的。

  在你開始構建音樂應用程式介面之前,我將一起陪你做一些練習。這看起來可能很無聊,但這是讓你徹底掌握Flexbox必經的過程,只有這樣才能讓你很擅長的使用Flexbox。

  說了這麼多的廢話,那我們趕緊的開始吧!(難怪篇幅長,原來開始有這麼的...(^_^))

 簡介

  CSS在過去的幾年裡已發生了很大的變化。CSS中引入了設計師喜歡的filters、transitions和transforms等。但有些東西已經消失了,可是我們都渴望這些東西能一直存在。

  使用CSS製作智慧的、靈活的頁面佈局一直以來都是CSSer想要的,也有很人使用各種不同的CSS黑魔法去實現智慧的頁面佈局。

  我們總是不得不忍受float、display:table這些佈局方式帶來的痛苦。如果你完寫過一段時間的CSS,你可能有相關體會。如果你沒有寫過CSS,那你是幸運的,在這也歡迎你來到CSS佈局中一個更美好的世界中!

  似乎設計師和前端開發人員的這次祈禱終於被上帝聽到了。而且這一次,在很大的風格上做出了改變。

  現在我們可以拋棄老司機們常用的CSS佈局的黑魔法。也可以和float以及display:table說拜拜。

  是時候去擁抱一個更簡潔的製作智慧佈局的現代語法。歡迎CSS Flexbox模組的到來。

 Flexbox是什麼

  根據規範中的描述可知道,Flexbox模組提供了一個有效的佈局方式,即使不知道視窗大小或者未知元素情況之下都可以智慧的,靈活的調整和分配元素和空間兩者之關的關係。簡單的理解,就是可以自動調整,計算元素在容器空間中的大小。

  這樣聽起來是不是太官方了,其實我也明白這種感覺。

 如何開始使用Flexbox

  這是每個人都會問的第一個問題,答案是比你預想的要簡單得多。

  開始使用Flexbox時,你所要做的第一件事情就是宣告一個Flex容器(Flex Container)。

  比如一個簡單的專案列表,我們常常看到的HTML形式如下所示:

<ul> <!--parent element-->
  <li></li> <!--first child element-->
  <li></li> <!--second child element-->
  <li></li> <!--third child element-->
</ul>

  一眼就能看出來,這就是一個無序列表(ul)裡有三個列表元素(li)。

  你可以把ul稱為父元素,li稱為子元素。

  要開始使用Flexbox,必須先讓父元素變成一個Flex容器。

  你可以在父元素中顯式的設定display:flex或者display:inline-flex。就這麼的簡單,這樣你就可以開始使用Flexbox模組。

  實際是顯式宣告瞭Flex容器之後,一個Flexbox格式化上下文(Flexbox formatting context)就立即啟動了。

  告訴你,它不是像你想像的那麼複雜。

  使用一個無序列表(ul)和一群列表元素(li),啟動Flexbox格式化上下文的方式如下:

/* 宣告父元素為flex容器 */
ul {
    display:flex; /*或者 inline-flex*/
}

  給列表元素(li)新增一點基本樣式,這裡你可以看到發生了什麼。

li {
    width: 100px;
    height: 100px;
    background-color: #8cacea;
    margin: 8px;
}

你  將看到的效果如下圖所示:

  你可能沒有注意到,但事實上已經發生了變化。現在已經是一個Flexbox格式化上下文。

  記住,預設情況下,div在CSS中垂直堆疊的,也就是說從上到下排列顯示,就像下圖這樣:

  上面的圖是你希望的結果。

  然而,簡單的寫一行程式碼display:flex,你立即就可以看到佈局改變了。

  現在列表元素(li)水平排列,從左到右。就像是你使用了float一樣。

  Flexbox模組的開始,正如前面的介紹,在任何父元素上使用display:flex。

  你可能不明白為什麼這一變化就能改變列表元素的排列方式。但我可以負責任的告訴你,你深入學習之後就能明白。現在你只需要信任就足夠了。

  理解flex display是使用Flexbox的一個開始。

  還有一件事情,我需要提醒您注意。

  一旦你顯式的設定了display屬性的值為flex,無序列表ul就會自動變成Flex容器,而其子元素(在本例中是指列表元素li)就變成了Flex專案。

  這些術語會一次又一次的提到,我更希望你通過一些更有趣的東西來幫助你學習Flexbox模組。

  我使用了兩個關鍵詞,我們把重點放到他們身上。瞭解他們對於理解後面的知識至關重要。

  • Flex容器(Flex Container):父元素顯式設定了display:flex
  • Flex專案(Flex Items):Flex容器內的子元素

  這些只是Flexbox模組的基礎。

 Flex容器屬性

flex-direction || flex-wrap || flex-flow || justify-content || align-items || align-content

  通過上面的內容,我們瞭解了一些基礎知識。知道了Flex容器和Flex專案是什麼,以及如何啟動Flexbox模組。

  現在是一個好好利用它們的時間了。

  有設定一個父元素作為一個Flex容器,幾個對齊屬性可以使用在Flex容器上。

  正如你的塊元素的width設定了200px,有六種不同的屬性可以用於Flex容器。

  好訊息是,定義這些屬性不同於你以往使用過的任何一種方法。

  flex-direction

  flex-direction屬性控制Flex專案沿著主軸(Main Axis)的排列方向。

  它具有四個值:

/* ul 是一個flex容器 */
ul {
    flex-direction: row || column || row-reverse || column-reverse;
}

  簡單點來說,就是flex-direction屬性讓你決定Flex專案如何排列。它可以是行(水平)、列(垂直)或者行和列的反向。

  從技術上講,水平和垂直在Flex世界中不是什麼方向(概念)。它們常常被稱為主軸(Main-Axis)和側軸(Cross-Axis)。預設設定如下所示。

  通俗的說,感覺Main-Axis就是水平方向,從左到右,這也是預設方向。Cross-Axis是垂直方向,從上往下。

  預設情況下,flex-direction屬性的值是row。它讓Flex專案沿著Main-Axis排列(從左向右,水平排列)。這就解釋了本文開始部分時無序列表的表現效果。

  儘管flex-direction屬性並沒有顯式的設定,但它的預設值是row。Flex專案將沿著Main-Axis從左向右水平排列。

  如果把flex-direction的屬性值修改成column,這時Flex專案將沿著Cross-Axis從上到下垂直排列。不再是從左向右排列。

  flex-wrap

  flex-wrap屬性有三個屬性值:

ul {
    flex-wrap: wrap || nowrap || wrap-reverse;
}

  我將通過一個例子來解釋如何使用flex-wrap屬性。首先在前面的無序列表的HTML結構中多新增幾個列表項li。

  將Flex容器設定適合大小以適合放置更多的列表專案或者說讓列表專案換行排列。這兩種方式,你是怎麼想的?

<ul> <!--parent element-->
    <li></li> <!--first child element-->
    <li></li> <!--second child element-->
    <li></li> <!--third child element-->
    <li></li>
    <li></li>
    <li></li>
</ul>

  幸運的是,新新增的Flex專案剛好適合Flex容器大小。也就是Flex專案能剛好填充Flex容器。

  再深入一點。

  繼續給Flex容器內新增Flex專案,比如說新增到10個Flex專案。這個時候會發生什麼?

  同樣的,Flex容器還是能容納所有的子元素(Flex專案)排列,即使瀏覽器出現了水平滾動條(當Flex容器中新增了很多個Flex專案,至使Flex容器的寬度大於視窗寬度)。

  這是每一個Flex容器的預設行為。Flex容器會在一行內容納所有的Flex專案。這是因為flex-wrap屬性的預設值是nowrap。也就是說,Flex專案在Flex容器內不換行排列。

ul {
    flex-wrap: nowrap; /*Flex容器內的Flex專案不換行排列*/
}

  no-wrap不是不可改變的。我們可以改變。

  當你希望Flex容器內的Flex專案達到一定數量時,能換行排列。當Flex容器中沒有足夠的空間放置Flex專案(Flex專案預設寬度),那麼Flex專案將會換行排列。把它(flex-wrap)的值設定為wrap就有這種可能:

ul {
    flex-wrap: wrap;
}

  現在Flex專案在Flex容器中就會多行排列。

  在這種情況下,當一行再不能包含所有列表項的預設寬度,他們就會多行排列。即使調整瀏覽器大小。

  就是這樣子。注意:Flex專案現在顯示的寬度是他們的預設寬度。也沒有必要強迫一行有多少個Flex專案。

  除此之外,還有一個值:wrap-reverse。

  是的,你猜對了。它讓Flex專案在容器中多行排列,只是方向是反的。

  flex-flow

  flex-flow是flex-direction和flex-wrap兩個屬性的速記屬性。

  你還記得使用border的速記寫法?border: 1px solid red。這裡的概念是相同的,多個值寫在同一行,比如下面的示例:

ul {
    flex-flow: row wrap;
}

  相當於:

ul {
    flex-direction: row;
    flex-wrap: wrap;
}

  除了這個組合之外,你還可以嘗試一些其它的組合。flex-flow: row nowrap,flex-flow: column wrap,flex-flow: column nowrap。

  我相信你瞭解這些會產生什麼樣的效果,要不嘗試一下。

  justify-content

  Flexbox模組真得很好。如果你仍然不相信它的魅力,那麼justify-content屬性可能會說服你。

  justify-content屬性可以接受下面五個值之一:

ul {
    justify-content: flex-start || flex-end || center || space-between || space-around
}

  justify-content屬性又能給我們帶來什麼呢?提醒你一下,你是否還記得text-align屬性。其實justify-content屬性主要定義了Flex專案在Main-Axis上的對齊方式。

  來看一個簡單的例子,還是考慮下面這個簡單的無序列表:

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>

  新增一些基本樣式:

ul {
    display:flex;
    border: 1px solid red;
    padding: 0;
    list-style: none;
    background-color: #e8e8e9;
}
li {
    background-color: #8cacea;
    width: 100px;
    height: 100px;
    margin: 8px;
    padding: 4px;
}

  你將看到的效果是這樣:

  通過justify-content屬性,可以讓Flex專案在整個Main-Axis上按照我自己的慾望設定其對齊方式。

  可能會有以下幾種型別。

  flex-start

  justify-content的預設屬性值是flex-start。

  flex-start讓所有Flex專案靠Main-Axis開始邊緣(左對齊)。

ul {
    justify-content: flex-start;
}

  flex-end

  flex-end讓所有Flex專案靠Main-Axis結束邊緣(右對齊)。

ul {
    justify-content: flex-end;
}

  center

  和你預期的一樣,center讓所有Flex專案排在Main-Axis中間(居中對齊)。

ul {
    justify-content: center;
}

  space-between

  space-between讓除了第一個和最一個Flex專案的兩者間間距相同(兩端對齊)。

ul {
    justify-content: space-between;
}

  你注意到有什麼不同?看看下圖的描述:

  space-around

  最後,space-around讓每個Flex專案具有相同的空間。

ul {
    justify-content: space-around;
}

  和space-between有點不同,第一個Flex專案和最後一個Flex專案距Main-Axis開始邊緣和結束邊緣的的間距是其他相鄰Flex專案間距的一半。看看下圖的描述:

  千萬不要覺得這些練習太多,這些練習可以幫助熟悉Flexbox屬性的語法。也能更好的幫助你更好的理解它們是如何影響Flex專案沿著Main-Axis的對齊方式。

  align-items

  align-items屬性類似於justify-content屬性。只有理解了justify-content屬性,才能更好的理解這個屬性。

  align-items屬性可以接受這些屬性值:flex-start || flex-end || center || stretch || baseline。

ul {
    align-items: flex-start || flex-end || center || stretch || baseline
}

  它主要用來控制Flex專案在Cross-Axis對齊方式。這也是align-items和justify-content兩個屬性之間的不同之處。

  下面是不同的值對Flex專案產生的影響。不要忘記這些屬性只對Cross-Axis軸有影響。

  stretch

  align-items的預設值是stretch。讓所有的Flex專案高度和Flex容器高度一樣。

  flex-start

  正如你所希望的flex-start讓所有Flex專案靠Cross-Axis開始邊緣(頂部對齊)。

  flex-end

  flex-end讓所有Flex專案靠Cross-Axis結束邊緣(底部對齊)。

  center

  center讓Flex專案在Cross-Axis中間(居中對齊)。

  baseline

  讓所有Flex專案在Cross-Axis上沿著他們自己的基線對齊。

  結果看上去有點像flex-start,但略有不同。那“baseline”到底是什麼呢?下圖應該能幫助你更好的理解。

  align-content

  還記得前面討論的wrap屬性嗎?我們在Flex容器中新增了更多的Flex專案。讓Flex容器中的Flex專案多行排列。

  align-content屬性用於多行的Flex容器。它也是用來控制Flex專案在Flex容器裡的排列方式,排列效果和align-items值一樣,但除了baseline屬性值。

  像align-items屬性一樣,它的預設值是stretch。你現在應該熟悉這些值。那它又是如何影響Flex容器裡的10個Flex專案多行排列方式。

  stretch

  使用stretch會拉伸Flex專案,讓他們沿著Cross-Axis適應Flex容器可用的空間。

  你看到的Flex專案間的間距,是Flex專案自身設定的margin值。

  flex-start

  之前你看到過flex-start。這次是讓多行Flex專案靠Cross-Axis開始邊緣。沿著Cross-Axis從上到下排列。因此Flex專案在Flex容器中頂部對齊。

  flex-end

  flex-end剛好和flex-start相反,讓多行Flex專案靠著Cross-Axis結束位置。讓Flex專案沿著Cross-Axis從下到上排列,即底部對齊。

  center

  你猜到了,center讓多行Flex專案在Cross-Axis中間。在Flex容器中居中對齊。

  這是Flex容器的最後一個屬性。你現在知道如何使用各種Flex容器屬性。你可以在工作中實踐這些屬性。

 Flex專案屬性

order || flex-grow || flex-shrink || flex-basis

  在前一節中,我解釋了Flex容器及其對齊屬性。

  確實漂亮。我想你也找到了感覺。現在我們把注意力從Flex容器轉移到Flex專案及其對齊屬性。

  像Flex容器,對齊屬性也可以用在所有的Flex專案。那我們開始吧。

  order

  允許Flex專案在一個Flex容器中重新排序。基本上,你可以改變Flex專案的順序,從一個位置移動到另一個地方。

  這不會影響原始碼。這也意味著Flex專案的位置在HTML原始碼中不需要改變。order屬性的預設值是0。它可以接受一個正值,也可以接受一個負值。

  值得注意的是,Flex專案會根據order值重新排序。從底到高。

  要說明總得需要一個例子。考慮下面這個無序列表:

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

  預設情況下,所有Flex專案的order值都是0。把前面給列表的樣式運用過來。看到的效果如下:

  Flex專案顯示是按HTML原始碼中的順序來顯示,Flex專案1、2、3和4。

  如果因為某些原因,在不改變HTML文件原始碼情況之下,想把Flex專案一從1變成最後。不能修改HTML文件原始碼意思是你不能把HTML程式碼改成:

<ul>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>1</li>
</ul>

  這個時候就需要order屬性。這個時候你需要把Flex專案一的order值設定比其他Flex專案值更大。

  如果你以前使用過z-index屬性,那你就能更好的理解這個屬性。

li:nth-child(1){
    order: 1; /*設定一個比0更大的值*/
}

  Flex專案就重新進行了排列,從低到高排列。不要忘記了,預設情況下,Flex專案2、3、4的order值為0。現在Flex專案1的order值為1。

  Flex專案2、3和4的order值都是0。HTML原始碼秩序並沒有修改過。如果給Flex專案2的order設定為2呢?

  是的,你猜對了。它也增加堆疊。現在代表Flex專案的最高的order值。

  當兩個Flex專案具有相同的order值呢?在下面的示例中,把Flex專案1和3設定相同的order值。

li:nth-child(1) {
    order: 1;
}
li:nth-child(3) {
    order: 1;
}

  現在仍是從低到高排列。這次Flex專案3排在Flex專案1後面,那是因為在HTML文件中Flex專案3出現在Flex專案1後面。

  如果兩個以下Flex專案有相同的order值時,Flex專案重新排序是基於HTML原始檔的位置進行排序。這個屬性就不做過多的解釋。接下來繼續介紹其他的屬性。

  flex-grow 和 flex-shrink

  Flex專案最優秀的一點就是靈活性。flex-grow和flex-shrink屬性允許我們玩這個靈活性。

  flex-grow和flex-shrink屬性控制Flex專案在容器有多餘的空間如何放大(擴充套件),在沒有額外空間又如何縮小。

  他們可能接受0或者大於0的任何正數。0 || positive number。

  接下來闡述它們的使用。使用一個簡單的無序列表做為例子,它只包含一個列表項。

<ul>
    <li>I am a simple list</li>
</ul>
ul {
    display: flex;
}

  新增更多的樣式,看起來像這樣:

  預設情況下,flex-grow屬性值設定為0。表示Flex專案不會增長,填充Flex容器可用空間。取值為0就是一個開和關的按鈕。表示flex-grow開關是關閉的。

  如果把flex-grow的值設定為1,會發生:

  現在Flex專案擴充套件了,佔據了Flex容器所有可用空間。也就是說開關開啟了。如果你試著調整你瀏覽器的大小,Flex專案也會縮小,以適應新的螢幕寬度。

  為什麼?預設情況下,flex-shrink的值是1,也就是說flex-shrink開關也是開啟的。

  可以仔細看看flex-grow和flex-shrink屬性在各種情況下的效果,這樣能更好的幫助你理解。

  flex-basis

  記得前面我說過,Flex專案是當我沒有的。但我們也可以控制。

  flex-basis屬性可以指定Flex專案的初始大小。也就是flex-grow和flex-shrink屬性調整它的大小以適應Flex容器之前。

  前面介紹的是非常生要的,所以我們需要花一點時間來加強對他們的理解。

  flex-basis預設的值是auto。flex-basis可以取任何用於width屬性的任何值。比如 % || em || rem || px等。

  注意:如果flex-basis屬性的值是0時,也需要使用單位。即flex-basis: 0px不能寫成flex-basis:0。

  這裡同樣使用只有一個列表項的列表做為示例。

<ul>
    <li>I am a simple list</li>
</ul>

ul {
    display: flex
}
li {
    padding: 4px; /*some breathing space*/
}

  預設情況,Flex專案的初始寬度由flex-basis的預設值決定,即:flex-basis: auto。Flex專案寬度的計算是基於內容的多少來自動計算(很明顯,加上了padding值)。

  這意味著,如果你增加Flex專案中的內容,它可以自動調整大小。

<ul>
    <li>I am a simple list AND I am a simple list</li>
</ul>

  然而,如果你想將Flex專案設定一個固定的寬度,你也可以這樣做:

li {
    flex-basis: 150px;
}

  現在Flex專案的寬度受到了限制,它的寬度是150px。

  它變得更加有趣。

  flex速記

  flex是flex-grow、flex-shrink和flex-basis三個屬性的速記(簡寫)。

  在適當的時候,我建議你使用flex,這樣比使用三個屬性方便。

li {
    flex: 0 1 auto;
}

  上面的程式碼相當於:

li {
    flex-grow: 0;
    flex-shrink: 1;
    flex-basis: auto;
}

  注意它們之間的順序。flex-grow第一,然後是flex-shrink,最後是flex-basis。縮寫成GSB,可以幫助你更好的記憶。

  如果flex屬性值中少一個值,會發生什麼呢?

  如果你只設定了flex-grow和flex-shrink值,flex-basis可能是預設值0。這就是所謂的絕對flex專案。只有當你設定了flex-basis,你會得到一個相對flex專案。

/* 這是一個絕對的Flex專案 */
li {
    flex: 1 1; /*flex-basis 預設值為 0*/
}
/* 這是一個相對的Flex專案 */
li {
  flex-basis: 200px; /* 只設定了flex-basis的值 */
}

  我知道你在想什麼。你肯定想知道相對和絕對的Flex專案是什麼?我將在後面回答這個問題。你只需要再次盲目信任就足夠了。

  讓我們看看一些非常有用的flex值。

  flex: 0 1 auto

li {
    flex: 0 1 auto;
}

  這相當於寫了flex預設屬性值以及所有的Flex專案都是預設行為。

  很容易理解這一點,首先看看flex-basis屬性。flex-basis設定為auto,這意味著Flex專案的初始寬度計算是基於內容的大小。

  明白了?

  把注意力放到下一個屬性,flex-grow設定為0。這意味著flex-grow不會改變Flex專案的初始寬度。也就是說,flex-grow的開關是關閉的。

  flex-grow控制Flex專案的增長,如果其值設定為0,Flex專案不會放大以適應螢幕(Flex容器大小)。

  最後,flex-shrink的值是1。也就是說,Flex專案在必要時會縮小。

  應用到Flex專案效果就是這樣子:

  注意:Flex專案沒有增長(寬度)。如果有必要,如果調整瀏覽器(調小瀏覽器寬度),Flex專案會自動計算寬度。

  flex: 0 0 auto

li {
    flex: 0 0 auto;
}

  這個相當於flex: none。

  還是老規矩:寬度是被自動計算,不過彈性專案不會伸展或者收縮(因為二者都被設定為零)。伸展和收縮開關都被關掉了。

  它基本上是一個固定寬度的元素,其初始寬度是基於彈性專案中內容大小。

  看看這個 flex 簡寫是如何影響兩個彈性專案的。一個彈性專案會比另一個容納更多內容。

  應該注意到的第一件事情是,這兩個彈性專案的寬度是不同的。因為寬度是基於內容寬度而自動計算的,所以這是預料得到的。

  試著縮放一下瀏覽器,你會注意到彈性專案不會收縮其寬度。它們從父元素中突出來了,要看到所有內容,必須橫向滾動瀏覽器。

  不要著急,稍後我會展示如何處理這種怪異的行為。

  在縮放瀏覽器時,彈性專案不會收縮,而是從彈性容器中突出來了。

  flex: 1 1 auto

  這與 flex: auto 專案相同。

  還是按我前面立的規矩。即,自動計算初始化寬度,但是如果有必要,會伸展或者收縮以適應整個可用寬度。

  伸展和收縮開關開啟了,寬度自動被計算。

  此時,專案會填滿可用空間,在縮放瀏覽器時也會隨之收縮。

  flex: "positive number"

  這裡正數可以代表任何正數(沒有引號)。這與 flex: “正數” 1 0 相同。

  flex: 2 1 0 與寫為 flex: 2 是一樣的,2 表示任何正數。

li {
    flex: 2 1 0; / *與 flex: 2相同 */
}

  與前面我立的規矩一樣,即,將彈性專案的初始寬度設定為零(嗯?沒有寬度?),伸展專案以填滿可用空間,並且最後只要有可能就收縮專案。

  彈性專案沒有寬度,那麼寬度該如何計算呢?

  這個時候 flex-grow 值就起作用了,它決定彈性專案變寬的程度。由它來負責沒有寬度的問題。

  當有多個彈性專案,並且其初始寬度 flex-basis 被設定為基於零的任何值時,比如 0px,使用這種 flex 簡寫更實用。

  實際發生的是,彈性專案的寬度被根據 flex-grow 值的比例來計算。

  考慮如下兩個列表項標記及 CSS:

<ul>
    <li>I am One</li>
    <li>I am Two</li>
</ul>

ul {
    display: flex;
}

/* 第一個彈性專案 */
li:nth-child(1) {
    flex: 2 1 0; /* 與寫成 flex: 2 相同*/
}

/* 第二個彈性專案 */
li:nth-child(2){
    flex: 1 1 0;
    background-color: #8cacea;
}

  記住設定 flex-grow : 1,會讓彈性專案填滿可用空間。伸展開關開啟了。

  這裡有兩個彈性專案。一個的 flex-grow 屬性值是 1,另一個是 2,那麼會出現啥情況呢?

  兩個專案上的伸展開關都開啟了。不過,伸展度是不同的,1 和 2。

  二者都會填滿可用空間,不過是按比例的。

  它是這樣工作的:前一個佔 1/3 的可用空間,後一個佔 2/3 的可用空間。

  知道是我怎麼得到這結果的麼?

  是根據基本的數學比例。"單項比例 / 總比例",我希望你沒有漏過這些數學課。

  看到出現啥情況了麼?

  即使兩個彈性專案內容一樣大(近似),它們所佔空間還是不同。寬度不是基於內容的大小,而是伸展值。一個是另一個的約兩倍。

有關於flex-grow、flex-basis和flex-shrink之間的詳細計算,可以點選@Chris Wright寫的《Flexbox adventures》博文。譯文可以點選這裡

  align-self

  align-self 屬性更進一步讓我們更好地控制彈性專案。

  你已經看到 align-items 屬性是如何有助於整體對齊彈性容器內的所有彈性專案了。

  如果想改變一個彈性專案沿著側軸的位置,而不影響相鄰的彈性專案,該怎麼辦呢?

  這是 align-self 屬性大展拳腳的地方了。

  該屬性的取值可以是這些值之一:auto || flex-start || flex-end || center || baseline || stretch。

li:first-of-type {
    align-self: auto || flex-start || flex-end || center || baseline || stretch
}

  這些值你已經熟悉過了,不過作為回顧,如下是它們如何影響特定目標專案。這裡是容器內的第一個專案。目標彈性專案是紅色的。

  flex-end

  flex-end將目標專案(Flex專案)對齊到Cross-Axis的末端。

  center

  center將目標專案(Flex專案)對齊到Cross-Axis的中間。

  stretch

  stretch會將目標專案拉伸,以沿著Cross-Axis填滿Flex容器的可用空間(Flex專案高度和Flex容器高度一樣)。

  baseline

  baseline將目標專案沿著基線對齊。它與flex-start的效果看起來是一樣的,不過我相信你理解了基線是什麼。因為前面已經解釋過。

  auto

  auto 是將目標Flex專案的值設定為父元素的 align-items值,或者如果該元素沒有父元素的話,就設定為 stretch。

  在下面的情況下,彈性容器的 align-items 值為 flex-start。這會把所有彈性專案都對齊到Cross-Axis的開頭。目標Flex專案現在繼承了 flex-start 值,即父元素的 align-item 值。

  如下是上面Flex專案的基礎樣式。這樣你可以對發生的事情理解得更好點。

ul {
    display: flex;
    border: 1px solid red;
    padding: 0;
    list-style: none;
    justify-content: space-between;
    align-items: flex-start;  /* 影響所有彈性專案 */
    min-height: 50%;
    background-color: #e8e8e9;
}

li {
  width: 100px;
  background-color: #8cacea;
  margin: 8px;
  font-size: 2rem;
}

  現在你差不多已經為有趣的部分做好準備了 :-)

 絕對和相對Flex專案

  前面瞭解了一些基本概念,但重要的是要澄清一些重要的概念。那絕對和相對Flex專案之間到底有啥區別呢?二者之間主要的區別在於間距及如何計算間距。

  一個相對Flex專案內的間距是根據它的內容大小來計算的。而在絕對Flex專案中,只根據 flex 屬性來計算,而不是內容。

  考慮如下的標記:

<ul>
    <li>
        This is just some random text  to buttress the point being explained.
    Some more random text to buttress the point being explained.
    </li>

    <li>This is just a shorter random text.</li>
</ul>

  兩個列表項元素,一個比另一個的文字多得多。

  加點樣式:

ul {
    display: flex; /*觸發彈性盒*/
}

li {
    flex: auto; /*記住這與 flex: 1 1 auto; 相同*/
    border: 2px solid red;
    margin: 2em;
}

  如下是結果:

  如果你已經忘了的話,flex: 1 1 auto 是與 flex-grow: 1、flex-shrink: 1 和 flex-basis: auto 相同的。

  Flex專案的初始寬度是被自動計算的(flex-basis: auto),然後會伸展以適應可用空間(flex-grow: 1)。

  當Flex專案因為被設定為 flex-basis: auto,而導致寬度被自動計算時,是基於Flex專案內包含的內容的大小而計算。

  上面示例中Flex專案的內容大小不相同。因此,Flex專案的大小就會不相等。

  既然各個寬度開始就不是相等的(它是基於內容的),那麼當專案伸展時,寬度也保持不相等。

  上面示例中的Flex專案是相對Flex專案。

  下面我們把Flex專案變成絕對的, 就是說這次它們的寬度是基於 flex 屬性,而不是內容的大小。一行程式碼就可以出奇跡。

li {
    flex: 1 ; /*與 flex: 1 1 0 相同*/
}

  效果如下:

  這次看到兩個Flex專案的寬度相同了嗎?

  Flex專案的初始寬度是零(flex-basis: 0),並且它們會伸展以適應可用空間。當有兩到多個Flex專案的 flex-basis 取值為0時,它們會基於 flex-grow值共享可用空間。

  這個之前就討論過了。現在寬度不會基於內容大小而計算,而是基於指定的 flex 屬性值來計算。這樣你就明白了吧。對麼?

  絕對Flex專案的寬度只基於 flex 屬性,而相對Flex專案的寬度基於內容大小。

 Auto-margin 對齊

  當心Flex專案上的 margin: auto 對齊。當在Flex專案上使用 margin: auto 時,事情看起來就很怪異了。

  你需要理解會發生什麼。它會導致不可預料的結果,不過我打算解釋解釋。

  當在Flex專案上使用 margin: auto 時,值為 auto 的方向(左、右或者二者都是)會佔據所有剩餘空間。

  這玩意有點難理解。下面我來說明一下。

  考慮如下的導航欄標記以及 CSS 樣式:

<ul>
    <li>Branding</li>
    <li>Home</li>
    <li>Services</li>
    <li>About</li>
    <li>Contact</li>
</ul>

ul {
    display: flex;
}
li {
    flex: 0 0 auto;
}

  你可以看到如下的效果:

  這裡有幾件事情要注意:

  • flex-grow 值為設定為0。這就解釋了為什麼列表項不會伸展。
  • Flex專案向Main-Axis的開頭對齊(這是預設行為)。
  • 由於專案被對齊到Main-Axis開頭,右邊就有一些多餘的空間。看到了吧?

  現在在第一個列表項(branding)上使用 margin: auto,看看會出啥情況。

li:nth-child(1) {
    margin-right: auto; /*只應用到右外邊距*/
}

  剛剛發生了什麼?之前的剩餘空間現在已經被分配到第一個Flex專案的右邊了。

  還記得我前面說的話吧?當在Flex專案上使用 margin: auto 時,值為 auto 的方向(左、右或者二者都是)會佔據所有剩餘空間。

  如果想讓一個Flex專案的兩邊都用自動外邊距對齊,該怎麼辦呢?

/* 如果願意的話,也可以用 margin 簡寫來設定兩個邊 */
li:nth-child(1) {
    margin-left: auto;
    margin-right: auto
}

  現在空白被分配到Flex專案的兩邊了。

  那麼,這是不是對很酷的自動外邊距對齊的一種折衷方案呢?看起來是。如果沒注意的話,它也可能是受挫之源。當在一個Flex專案上使用自動外邊距(margin: auto)時,justify-content 屬性就不起作用了。

  例如,在上面的Flex容器上通過 justify-content 屬性,設定不同的對齊選項時,對佈局沒有影響。

ul {
    justify-content: flex-end;
}

 Flexbox實戰

  導航系統是每個網站或者應用程式的重要組成部分。這個世界上的每個網站都會有某種導航系統。

  下面我們看看這些熱門網站,以及它們是如何實現其導航系統的。你看到Flexbox是如何幫助你更高效地建立這些佈局嗎?

  也仔細看看哪裡會用得上自動外邊距特性。

  Bootstrap導航

  AirBnB PC端導航

  Twitter PC端導航

  建議你自己寫程式碼。試著自己實現這些導航系統。現在你已經掌握了所需的所有知識。你所需要的是一點勇氣去開始寫。

  下一節再見。但願在你已經完成了導航系統練習之後。

 切換flex-direction會發生什麼?

  提醒一下:將會有一些奇怪的東東出現。

  在入手學習Flexbox時,這個部分是最惱火的。我估計很多彈性世界的新手也會發現如此。

  還記得我說過預設的Main-Axis方向是從左到右,Cross-Axis方向是從上到下吧?

  好吧,現在你也可以改變這個方向。

  正如在較早的小節中所描述的那樣,用 flex-direction: column 時,確實是這樣。

  當用 flex-direction: column 時,Main-Axis和Cross-Axis會向如下所看到的那樣改變:

  如果曾用英語寫過文字,那麼你就知道英語是從左到右,從上到下來寫的。

  Flexbox的預設Main-Axis和Cross-Axis也是採用同樣的方向。

  不過,如果將 flex-direction 切換為 column,它就不再遵循英語的正規化,而是日語的正規化!

  是的,日語。

  如果你用日語寫過文字,那麼應該很熟悉了。(鄭重宣告,我從沒用過日語寫過文字)。

  日文通常是從上到下寫的!沒那麼怪,對吧?

  這就解釋了為嘛這對英語寫作者可能有點惱火。

  看看下面這個例子。標準無序列表(ul),帶有 3 個列表項(li)。不過這次我要改變一下flex-direction。

<ul>
    <li></li>
    <li></li>
    <li></li>
</ul>

ul {
    display: flex;
    flex-direction: column;
}

  如下是方向變化之前的樣子:

  如下是方向變化之後的樣子:

  出啥事了?

  現在文字是以日語風格寫的:沿Main-Axis從上到下。

  我很樂意指出,你會發現一些有趣的事情。

  你會看到專案的寬度填滿了空間,對吧?

  如果在之前要變成這樣子,得處理 flex-basis 以及 flex-grow 屬性。

  下面來看看這些會如何影響新的佈局。

li {
    flex-basis: 100px;
}

  下面是你會得到的。

  什麼?高度是被影響了,但是寬度沒有啊?我之前說過,flex-basis 屬性定義每個Flex專案的初始寬度。

  我是錯的,或者這樣說更好:我是用英語來思考。下面我們姑且切換到用日語思考。並且總是得有寬度。

  在切換 flex-direction 時,請注意,影響Main-Axis的每一個屬性現在會影響新Main-Axis。像 flex-basis 這種會影響Main-Axis上Flex專案寬度的屬性,現在會影響專案的高度,而不是寬度。

  方向已經被切換了!

  所以,即使你使用 flex-grow 屬性,它也是影響高度。本質上,每個作用於橫向軸(即Main-Axis)上的 flex 屬性,現在都會作用於縱向上的新Main-Axis。它只是在方向上的一個切換。

  這裡再來一個例子。我發誓在這個例子之後你會有更好的理解。減少之前看到過的Flex專案的寬度,它們就不再填滿整個空間了:

li {
    width: 200px;
}

  如果想把列表項移到螢幕中間該怎麼辦呢?

  在英語中,這是你到目前為止處理彈性容器的方式。就是說, 把Flex專案移到Main-Axis的中間 。

  所以,你會用 justify-content: center。但是這樣做不起作用。因為方向變了,中心是沿著Cross-Axis,而不是Main-Axis。

  再來看看:

  所以請用日語文字來思考。Main-Axis是從上到下,你不需要這樣。Cross-Axis是從左到右。貌似是你所要的。

  你需要 把Flex專案移到Cross-Axis的中間 。這裡想起哪個Flex容器屬性了麼?

  是的,align-items 屬性。align-items 屬性處理Cross-Axis上的對齊。

  所以要把這些專案移到中間,得這樣做:

li {
    align-items: center;
}

  瞧瞧!Flex專案已經居中了吧。

  是有點懸乎,我知道。如果需要,就再複習一遍好了。在研究Flexbox時,我發現很多 CSS 書都略過了這一部分。

  用日語文字來思考一下會有很大幫助。我們有必要了解,所有Flexbox屬性都是基於合適的 flex-direction 起作用。

  相信你又學到了一點新東西。我很開心解釋這些,希望你也很開心。

 我的天啦,彈性盒解決了那問題了?

  很多設計師用 CSS 時遇到的一些典型問題已經被Flexbox輕而易舉解決了。

  @Philip Walton 在其 Flexbox解決了的問題這個專案 列出了 6 種典型的問題(到本文編寫時)。

  他全面討論了之前用 CSS 的限制,以及目前Flexbox提供的解決方案。建議在完成本文後看一看。

  在接下來的實踐環節中,在開始用彈性盒建立一個音樂應用佈局時,我會解釋他提出的一些概念。

  Flex 不相容瀏覽器的坑

  如果你不是在夢中寫 CSS 的那一類人的話,就可能想看看這個 Github 倉庫

  有些比我聰明的人在這裡維護了一個Flexbox的 bug 列表及其變通方法。當有些事情沒有按預期起作用時,這是我看的第一個地方。我也會在後面的實踐環節中帶你踩踩一些顯眼的坑。

@Philip Walton早前專門寫了一篇有關於解決Flexbox跨瀏覽器相容Bug的文章《Normalizing Cross-browser Flexbox Bugs》,對應的譯文可以點選這裡閱讀

 用彈性盒建立一個音樂應用的佈局

  在學習完了乏味嚴謹的基礎知識之後,該有一些有趣的專案了。是時候玩玩實際的例子,並把剛獲得的Flexbox技能用上去。

  想出一個好專案花了我好幾天。由於缺乏創造性的選擇,我想出了一個貓玩的音樂應用佈局。我稱它為 catty music 。

  也許到了 2036 年,我們就能讓貓在火星上的某個地方唱搖滾。如下是完成了的佈局看起來的樣子,並且完全是用Flexbox佈局的。

  可以線上上看,在這裡

  如果在移動裝置上看,外觀會稍微有點不同。這是在本文響應式設計一節中要解決的問題。

  不過,有件事我得坦白。我已經做了許多人認為是錯誤的事情。我完全用Flexbox建立整個佈局。

  出於多種理由,這樣做可能並非那麼理想。但是在這種情況下是故意的。我只是想用一個專案,向你展示所有可以用Flexbox做的事情。

  如果你好奇什麼時候使用Flexbox是對的,什麼時候是錯的,那你可以讀讀我寫的一篇文章。

Flexbox 很棒,不過它在這裡不受歡迎 Flexbox 毋庸置疑是我們大多數人遇到的最好的東西(如果你寫 CSS 的話),不過它是不是適合所有情況呢…

  這裡,我心裡的石頭終於落地了。現在我相信在讀完這個之後,沒人會對我大呼小叫了。

  Catty Musci 中的一切都是用Flexbox佈局, 這是故意儘可能地炫技。

  所以下面我們開始把這個玩意建成!對於任何稍微合理一點的專案來說,有點規劃對避免效率低下是有幫助的。就讓我帶你看看建立 Catty Music 佈局的規劃方法。

  從哪裡開始?

  只要用Flexbox建立佈局,就應該從找出佈局中哪一個部分會作為Flex容器開始。然後才可以使用Flexbox提供的強大對齊屬性。

  分析

  你可以讓整個包含體作為Flex容器(下圖中被包含在紅色邊框內的部分),並把佈局的其它部分分成Flex專案(Item 1 和 Item 2)。

  這樣做完全說得通,讓 Item 1 包含佈局中除了腳註以外的每個部分。腳註部分用來包含音樂控制按鈕。

  你知道Flex專案也可以成為Flex容器嗎?是的,是可能的!

  你想巢狀多深就巢狀多深(不過理智的做法是保持一個合理的水平)。於是,根據這個新啟示就有了這個...

  Item 1(第一個Flex專案)也可以弄成一個Flex容器。然後,側邊欄(Item 1b)和主欄目(Item 1a)就成了 Item 1 的Flex專案。

  你依然與我同在,對吧?像這樣拆分佈局,會給你一個相當不錯的心理模型來處理。

  在用Flexbox開始建立更為複雜的佈局時,你會看到這有多重要。當然,你並不需要一個像上面那樣高大上的影象。在紙上畫一個簡單的草圖就足夠了。

  記得我說過可以想巢狀多深就巢狀多深吧?貌似這裡還可以再來一個巢狀。

  看看上面的主欄目(Item 1a)。它也可以變成一個Flex容器,以容納如下高亮度的部分:Item 1a — A 和 Item 1a — B。

  可能你會決定不把主欄目(Item 1a)變成Flex容器,只在其內部放入兩個 div 來容納高亮度部分。

  是的,這樣做沒問題,因為 “Item 1a — A” 和 “Item 1a — B” 是垂直堆放的。

  預設情況下,div 是垂直堆放的。這是盒模型的工作原理。如果選擇把主欄目變成一個Flex容器,就有了隨時可你供調遣的強大對齊屬性。

  Flexbox中的 Flex 是指彈性、靈活。Flex容器預設是彈性的,跟響應式有點類似。這也許是使用Flex容器,而不是普通 div 的另一個原因。不過,這取決於實際情況。

  在你建立 Catty Music 時我會論及一些事情事情。你現在應該去寫點程式碼了。

  HTML結構

  從如下的基礎 HTML 設定開始。

<!DOCTYPE html>
<html>
    <head>
        <title>Catty Music</title>
    </head>
    <body>

        <main></main> <!--用來包含應用的主欄目-->

        <footer></footer> <!--用來包含音樂控制按鈕和歌曲細節-->

    </body>
</html>

  然後為它設定樣式:

html,
body {
    height: 100%; /*顯式設定這,是很重要的*/
}

body {
    display: flex; /*flex 超能力被啟用了! */
    flex-direction: column; /*垂直而不是水平堆放彈性專案(主欄目和腳註元素)*/
}

  使用Flexbox的第一個步驟就是確定一個Flex容器。

  這正好是上面程式碼所做的。它將 body 元素的 display 屬性設定為 flex。現在有了一個Flex容器,即 body 元素。

  Flex專案也被定義了(item 1 和 item 2):跟前面分析中所做的一樣。

  注意,如果你對這個概念還是有點模糊,就應該再看看我在之前開始分析時展示的影象。

  盯著最後的影象,你應該讓彈性專案工作起來。

  讓腳註吸附在底部。讓放音樂控制的腳註吸附在頁面的底部,同時讓主欄目填滿剩餘空間。

  你怎麼實現?

main {
    flex: 1 0 auto; /*填滿剩餘空間*/
}

footer {
    flex: 0 0 90px; /*不會放大或者收縮 - 只會固定在 90px 高度。*/
}

  請看上面列出的程式碼中的註釋。多虧了 flex-grow 屬性,它讓主欄目填滿整個空間相對很容易。只需將 flex-grow 屬性的值設定為 1 即可。還應該把 flex-shrink 屬性設定為 0。為什麼呢?

  因為 flex-direction 沒有改變,所以原因也許不很明顯。

  在有些瀏覽器中,會有一個 bug,允許Flex專案收縮後比其內容尺寸小。這是個很古怪的行為。

  解決這個 bug 的變通方案是把 flex-shrink 的屬性值設定為 0,而不是預設值 1,同時,把 flex-basis 屬性設定為 auto。

  就像是說:請自動計算Flex專案的大小,但是不要收縮。有了這個簡寫值,就可以得到Flex專案的預設行為。

  Flex專案會隨著瀏覽器縮放那個收縮。縮放不是基於 flex-shrink屬性,而是基於自動對Flex專案的寬度重新計算(flex-basis: auto)。

  這會導致Flex專案至少與它的寬度或者高度(如果宣告瞭)或者預設內容尺寸一樣大。請不要忘記我在分析 flex 簡寫屬性時設立的原則。後面會有更多簡寫的東西。

  現在事情彙集到一起了,下面我們放點樣式來定義間距和顏色。

body {
    display: flex;
    flex-direction: column;
    background-color: #fff;
    margin: 0;
    font-family: Lato, sans-serif;
    color: #222;
    font-size: 0.9em;
}

footer {
    flex: 0 0 90px;
    padding: 10px;
    color: #fff;
    background-color: rgba(61, 100, 158, .9);
}

  依然沒有啥奇蹟。你將看到的效果如下圖所示:

  看看事情是如何開始初具規模,你會讓它變得更好一點。

  固定側邊欄

  如果你是跟著寫程式碼,就更新一下你的 HTML 文件。

<main>
    <aside> <!--這代表側邊欄,其中包含了來自 font-awesome 的圖示集-->
        <i class="fa fa-bars"></i>
        <i class="fa fa-home"></i>
        <i class="fa fa-search"></i>
        <i class="fa fa-volume-up"></i>
        <i class="fa fa-user"></i>
        <i class="fa fa-spotify"></i>
        <i class="fa fa-cog"></i>
        <i class="fa fa-soundcloud"></i>
    </aside>

    <section class="content"> <!--這一部分會容納除側邊欄以外的所有東西-->
    </section>
</main>

  上面的程式碼列表已經解釋的很清楚了。

  至於圖示設定,我用了熱門的 Font Awesome 庫。這樣用你想要的圖示就簡單到只需新增一個 CSS 類即可。這就是我在 aside 標記中所做的事情。

  正如之前解釋過的,上面的 main 部分也會成為一個Flex容器。側邊欄(用 aside 標記表示) 以及 section 會成為Flex專案。

main {
  flex: 1 0 auto; /* 變成一個彈性專案*/
  display: flex; /*只包含這一行,現在就有一個彈性容器,帶有彈性專案:側邊欄和主內容區*/
}

  很好,越來越有意思了,嘿嘿。

  現在,主欄目是一個Flex容器了。下面我們來處理它的Flex專案之一,側邊欄。跟讓腳註吸附到頁面底部一樣,你還會想讓側邊欄吸附到頁面的左邊。

aside {
    flex: 0 0 40px; /*不會放大或者縮小。固定在 40px*/ 
}

  側邊欄應該讓圖示垂直堆放。可以讓側邊欄變成Flex容器,給它設一個 flex-direction,讓所有圖示垂直堆放。然後應用一個對齊屬性,讓圖示就位。

  在下面的程式碼列表中,看看你可能會怎麼做。

aside {
    /* ...  */
    display: flex; /*現在也是一個彈性容器*/
    flex-direction: column; /*垂直堆放圖示*/

    /*因為方向改變了,如下在垂直方向上起作用。*/
    justify-content: space-around;

    align-items: center; /*方向改變了!這條影響的是水平方向。將圖示居中*/
    background-color: #f2f2f2; /*讓我變漂亮*/
}

aside i.fa {
    font-size: 0.9em;  /*圖示的字型大小*/
}

  我已經在上面的程式碼中加了很多註釋,現在看看佈局是如何漂亮。很乾淨,只有幾行程式碼。合情合理的程式碼,沒有亂七八糟的招數。

  主內容區目前是空的。不要忘記它是第二個列表項,側邊欄是第一個。給這裡放一下東西。給主內容區新增內容你可以再看看完工的專案,這樣就不會忘記接下來要發生的事情。

  更重要的是,這能幫助你理解下面的程式碼。更新 HTML 文件,在 .content 部分新增如下標記:

<section class="content"> <!--這一區是空的,用內容填充它-->

    <div class="music-head"> <!--第一個列表項:包含音樂詳情-->

        <img src="images/cattyboard.jpg" /><!--專輯封面-->

        <section class="catty-music"> <!--專輯的其它細節-->
            <div>
                <p>CattyBoard Top 100 Single Charts (11.06.36)</p>
                <p>Unknown Artist</p>
                <p>2016 . Charts . 100 songs</p>
            </div>

            <div> <!--Music controls-->
                <i class="fa fa-play">Play all</i>
                <i class="fa fa-plus">Add to</i>
                <i class="fa fa-ellipsis-h">More</i>
            </div>
        </section>

    </div> <!--end .music-head-->

    <!--第二個列表項:包含專輯中的歌曲列表-->
    <ul class="music-list">  
        <li>
            <p>1. One Dance</p>
            <p>Crake feat CatKid & Cyla</p>
            <p>2:54</p>
            <p><span class="catty-cloud">CATTY CLOUD SYNC</span></p>
        </li>
        <li>
            <p>2. Panda</p>
            <p>Cattee</p>
            <p>4:06</p>
            <p><span class="catty-cloud">CATTY CLOUD SYNC</span></p>
        </li>
        <li>
            <p>3. Can't Stop the Feeling!</p>
            <p>Catin Cimberlake</p>
            <p>3:56</p>
            <p><span class="catty-cloud">CATTY CLOUD SYNC</span></p>
        </li>
        <li>
            <p>4. Work From Home</p>
            <p>Cat Harmony feat Colla</p>
            <p>3:34</p>
            <p><span class="catty-cloud">CATTY CLOUD SYNC</span></p>
        </li>
    </ul>
</section>

  嗯,我比上次新增了更多的東西,不過很簡單。我用一個 div 填充空內容部分,這個 div 用來容納 catty 專輯的封面和其他細節。ul 容納專輯的歌曲列表。列表中用單獨的段落來容納歌曲標題、藝術家、時長、"_catty cloud sync“。

  那麼你打算如何設定樣式呢?看看我怎麼做的?

  首先,應該讓 .content 部分成為Flex容器。

.content {
    display: flex;
    flex: 1 0 auto; /*這確保本區伸展到填滿可用空間*/
    flex-direction: column;
}

  還應該處理它的Flex專案:

.music-head {
    flex: 0 0 280px; /*相同的備忘,不要伸展或收縮 - 固定為 280px*/
    display: flex;  
    padding: 40px;
    background-color: #4e4e4e;
}

.music-list {
    flex: 1 0 auto;
    list-style-type: none;
    padding: 5px 10px 0px;
}

  .music-head 容納專輯封面以及其它專輯細節。相同的備忘錄,不要伸展或者收縮,保持高度為 280px。高度?沒有寬度?是的!

  父元素已經切換了 flex-direction。隨後需要讓它變成一個彈性容器,所以寫上 display: flex。.music-list 容納歌曲列表,填滿與上面的 .music-head 共享的剩餘可用空間。

  這依然沒讓人覺得有多漂亮,不過來吧,如果你還跟著,你做的很不錯了。贊一下。

  這裡有幾個問題。

  歌曲列表看起來很糟糕

  包含音樂封面的部分有真的很難看的文字

  我會再次來你解決這些問題。

  下面是我提出的解決方案。

  處理歌曲列表

  每個歌曲列表包含 4 個段落,歌名、藝術家、時長和 “catty cloud sync”。

  一定有辦法讓所有這些放在一行,每個段落佔據該行相等空間。用Flexbox來搞定!這裡的概念與很多柵格系統中用的一樣。

li {
  display: flex; /*段落現在顯示在一行上*/
  padding: 0 20px; /*留點呼吸空間*/
  min-height: 50px;
}

li p {
  flex: 0 0 25%; /*這是甜麵醬*/
}

  看到段落會發生什麼了嗎?

flex: 0 0 25%;

  “不要伸展或者收縮,不過每個段落應該佔據 25% 的可用空間” 。段落所佔空間是相等的。

  使用這種技術

  這種技術是很有用的。可以用它來建立不相等的內容區。比如,兩欄檢視。

  一個欄目可以佔可用空間的 60%,另一個佔 40%:

.first-section: 0 0 60%;
.second-section: 0 0 40%;

  可以用這種技術建立柵格系統。你將看到的效果如下:

  給列表交替的顏色,也處理一下 “catty cloud sync” 標籤。

li span.catty-cloud {
  border: 1px solid black;
  font-size: 0.6em;
  padding: 3px;
}

li:nth-child(2n) {
  background-color: #f2f2f2;
}

  所以,你征服它了,開始更好理解Flexbox方言了。這是你現在應該得到的東西了。

  現在要處理第二個問題了。讓相簿詳情文字看著更好看點。下面真是很簡單的事情。

.catty-music{
    flex: 1 0 auto;
    display: flex;
    flex-direction: column;
    font-weight: 300;
    color: #fff;
    padding-left: 50px;
}

.catty-music div:nth-child(1){
    margin-bottom: auto;
}

.catty-music div:nth-child(2){
    margin-top: 0;
}

.catty-music div:nth-child(2) i.fa{
    font-size: 0.9em;
    padding: 0 0.7em;
    font-weight: 300;
}
.catty-music div:nth-child(1) p:first-child{
    font-size: 1.8em;
    margin: 0 0 10px;
}

.catty-music div:nth-child(1) p:not(:first-child){
    font-size: 0.9em;
    margin: 2px 0;
}

  你做到了,而且做的相當不錯。

  一個快速練習

  我留下腳註部分給你作為練習。試著自己解決腳註。只需採用相同的技術。你知道你能搞定嗎?如果卡住了,可以檢視 Catty Music 的完整原始碼。你也可以把整個腳註分成Flex專案,從這裡開始。

  簡直不相信你到了這一步。下面,你會看到Flexbox是如何有助於響應式設計。

 Flexbox用於響應式設計

  已經有不少關於響應式設計的書,有不少書還不錯。

  因為本文專注於Flexbox,所以我不會深入響應式設計。

如果你從未接觸過任何關於響應式設計相關的知識,建議你點選這裡進行了解

  像我之前在某處說過的那樣,用Flexbox,我們確實得到了一些開箱即用的響應性。

  Flexbox就像 彈性的盒子 。不過,可以通過媒體查詢搞定不同的螢幕尺寸,然後改變彈性行為。

  如下是一個示例。我們又用簡單無序列表來幫忙。

<ul>
    <li>Home</li>
    <li>About</li>
    <li>Contact</li>
    <li>Register</li>
    <li>Login</li>
  </ul>

  並且設定點樣式...

ul {
    list-style-type: none;
    display: flex;
    border: 1px solid #4e4e4e;
}

li {
    flex: 0 0 auto;
    padding: 10px;
    margin: 10px;
    background-color: #8cacea;
    color: #fff;
    font-size: 1em;
}

  現在你已經是Flexbox專家了,所以你知道是咋回事。

  如下是導航欄的樣子。

  這對於桌面以及平板電腦可能還挺酷,不過在某些螢幕尺寸上,就特別難看。在移動裝置上,你會想讓導航條目垂直堆放。然後媒體查詢就登堂入室了。

@media screen and (max-width: 769px) {
    /* 這裡的程式碼只適用於寬度小於 769px 的螢幕裝置*/
    ul {
        flex-direction: column; /* 在更小的裝置上,切換方向*/
    }
}

  如果在這之前,你對響應式設計還懂那麼點,那就太棒了。把Flexbox納入你已有的知識好了。

  順便說一句,我假設你理解媒體查詢是什麼。如果不理解的話,看看下面的簡介。

  媒體查詢

  媒體查詢是響應式設計的核心,讓你可以以特定螢幕尺寸為目標,單獨指定執行在該裝置上的程式碼。

  使用媒體查詢最流行的形式是 @media 規則。

  它看起來是這樣的:

@media screen and (max-width: 300px) {
  /*在這個程式碼塊中寫 CSS*/
}

  看著這段程式碼,猜都可以猜到它的作用。

  "對於最大寬度為 300px 的螢幕裝置… 做這做那"

  在該程式碼塊中的任何樣式都將適用於匹配表示式的裝置,即 “screen and (max-width: 300px)” 。

  我猜這有助於消除一些疑惑。

  快速練習

  Catty music 在移動裝置上的顯示有所不同。這可是個好訊息。更棒的是你應該試著重新建立它。

  如果你遇到了難題,本教程程式碼庫的連結在下一節。解決方案也在倉庫中。快到最後了!在總結部分,我將討論瀏覽器支援、有用的連結和幫助你上手的資源。

 總結

  你已經學習瞭如何使用Flex容器和Flex專案的對齊屬性。我引導你理解了絕對和相對彈性、自動外邊距對齊以及切換彈性方向。你還有機會將Flexbox技能應用到建立 Catty Music 應用,然後我也提到了響應式設計。

  這確實是一段漫長的旅程。

  現在,我會向你解釋一些最終的概念。用一些我認為你會發現很有用的資源和連結幫助你。

  Flexbox的瀏覽器支援

  這是當傾向於在生產中使用Flexbox時,被問到的一個常見的問題。這問題我也沒法很好回答,不過 caniuse 網站能很好處理這個問題。

  如下是一個來自 caniuse 的螢幕截圖,瀏覽器支援很棒。你可以在這裡自己看

  在我職業生涯早期,我瀏覽過 caniuse 很多次,依然沒法掌握表示的資料是什麼意思。所以這裡有一個簡單的解釋。

  caniuse 網站的右下角是一個圖例。

  看看上面的影象,或者就訪問一下網站,找到圖例,就明白了。實際上就是這麼回事。

  本文根據@Ohans Emmanuel的《Understanding Flexbox: Everything you need to know》所譯,整個譯文帶有我們自己的理解與思想,如果譯得不好或有不對之處還請同行朋友指點。

  譯文:http://www.w3cplus.com/css3/understanding-flexbox-everything-you-need-to-know.html

相關文章