1. 程式人生 > >[CSS七分鐘系列]都1902年了,還不知道用margin:auto給flex容器內元素分組?

[CSS七分鐘系列]都1902年了,還不知道用margin:auto給flex容器內元素分組?

最近看到幾篇博文講解margin:auto在flex容器中的使用,可惜的是大多講解都浮於頁面表現,沒深究其中的作用機理,本文在此淺薄對其表現機理做簡單探討.

 

引子


日常業務迭代過程中,flex已經是前端工程師解決常見佈局的神兵利器.但是隨著使用的深入,偶然會發覺flex對於簡單的佈局足夠直接迅速,但是對於稍稍複雜一些的佈局,就需要層層的包裹分組來解決.舉個栗子,下圖是我們常見的佈局圖:

 

如果flex容器之中僅僅只有三個元素,彼此分離,我們藉助於justify-content就足夠應付.但是如果其中兩個元素需要當成一組來處理,比如圖一中的BC,使用flex佈局,就不能保證佈局結構足夠簡單,就需要把AB用一個div之類的標籤包括起來當成一個元素,並且BC需要在新的包裹容器中居中,才可以實現上圖佈局.程式碼如下:

<div class="flex-container">
  <div class="A">A</div>
  <div class="BC">
    <div class="B">B</div>
    <div class="C">C</div>
  </div>
  <div class="D">D</div>
</div>
.flex-container {
  display: flex;
  justify-content: space-between;
}
.A {
  background: #FFE6CC;
  width: 100px;
}
.BC {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
}
.B {
  background: #FFF2CC;
  width: 100px;
}
.C {
  background: #F8CECC;
  width: 100px;
}
.D {
  background: #E1D5E7;
  width: 100px;
}

那麼有沒有比上面更簡單的佈局方式麼?有,那就是使用margin:auto.

 

使用margin:auto給元素分組

 

如果使用margin:auto的話,那麼怎麼更加簡單實現上圖的佈局.
下面是佈局程式碼.

<div class="flex-container">
  <div class="A">A</div>
  <div class="B">B</div>
  <div class="C">C</div>
  <div class="D">D</div>
</div>
.flex-container {
  display: flex;
  justify-content: space-between;
}
.A {
  background: #FFE6CC;
  width: 100px;
}
.B {
  background: #FFF2CC;
  width: 100px;
  margin-left: auto;
}
.C {
  background: #F8CECC;
  width: 100px;
  margin-right: auto;
}
.D {
  background: #E1D5E7;
  width: 100px;
}

相對與引子中的程式碼來說,圖中標紅的是改動的地方.
主要是下面三個改動:

  • 去掉外層flex中的justify-content屬性.[margin:auto優先順序比justify-content高,會使此屬性失效,所以刪除]

  • 簡化html結構.原來需要三層結構,簡化後只需要兩層.

  • B的margin-left和C的margin-right設定為auto.

 

 

機理探討

 

最好的原理說明在css的規範中.我們首先查閱規範中對於flex容器margin:auto的說明[資源來源可參閱文末的參考資料].

 

 

規範中明確說明了兩個重要的點,:

  • margin:auto優先順序比 justify-content,align-self優先順序高

  • 如果正常分配空間之後,仍然有未分配的空間,剩下的空間將分配給margin:auto的元素.


但是此規範沒有說明,如果有多個margin:auto的元素,空間將如何分配?對此,mdn文件有說明[資源來源可參閱文末的參考資料]:

 

 

mdn明確告知,空間將會平均分配給margin:auto的元素.
總結來看,就是可以使用margin:auto在flex容器主軸方向給子元素的左右兩側分配空間.

 

更多示例

 

1. 設定外邊距auto越多,分配數量越多

 

到此有看官可能有疑問了,如果flex容器,一個子元素margin-left,margin-right都設定為auto,另外一個子元素僅僅只設定了margin-left,那麼空間該如何分配.實測證明,在主軸方向上,有幾個外邊距(指margin-left,margin-right)設定為auto,那麼就分幾份.

 

.flex-container {
  display: flex;
}
.A {
  background: #FFE6CC;
  width: 100px;
}
.B {
  background: #FFF2CC;
  width: 100px;
  margin-left: auto;
  margin-right: auto;
}
.C {
  background: #F8CECC;
  width: 100px;
  margin-left: auto;
}
.D {
  background: #E1D5E7;
  width: 100px;
}

 

上述程式碼顯示效果如下:

 

B因為左右兩個外邊距都是auto,所以會各佔一份,C因為只有左邊距是auto,因此只佔用一份.

 

2. flex列容器

 

上面的舉例主軸都是水平方向.那麼主軸是豎直方向的是否也適用呢?這裡可以肯定回答: 列容器margin:auto仍然有效.不過需要把margin-left,margin-right改成設定 margin-top,margin-bottom為auto.

 

.flex-container {
  display: flex;
  flex-direction: column;
  height: 500px;
}
.A {
  background: #FFE6CC;
  width: 100px;
}
.B {
  background: #FFF2CC;
  width: 100px;
  margin-top: auto;
}
.C {
  background: #F8CECC;
  width: 100px;
  margin-bottom: auto;
}
.D {
  background: #E1D5E7;
  width: 100px;
}

 

 

上述程式碼顯示效果如下:

 

 

從示例中可以看出,margin:auto有空間佔有效應. 使用margin:auto在某些情況下可以替代 flex:1, justify-content: space-between等的使用.這裡不再展開闡釋.

 

總結

margin:auto適合用來給flex容器的子元素間(在主軸方向)增加空間,適當的使用margin:auto可以簡化dom的佈局結構以及樣式程式碼,提高程式設計效率.

參考資料

[1] w3c css-flexbox規範: https://www.w3.org/TR/css-flexbox-1/#auto-margins

[2] mdn關於margin:auto對flex容器的影響說明: https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-left

  

 

  微信搜尋 ''十八將君'',關注我的公眾號和我一起成長~

&n